From 990e4e0d44c81b7d0b45892e19afa7e0f1a3460c Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 14 Jun 2015 05:42:47 +0200 Subject: [PATCH 001/113] log polarity --- libethereum/Client.cpp | 37 ++++++++++++++++++++++++------------- libethereum/Client.h | 11 ++++++++++- libevm/ExtVMFace.h | 6 ++++-- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 9d2c9a9e6..e25eb0d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -480,7 +480,7 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& } } -void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) +void Client::appendFromBlock(h256 const& _block, bool _polarity, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. auto d = m_bc.info(_block); @@ -503,7 +503,7 @@ void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) auto transactionHash = transaction(d.hash(), j).sha3(); // filter catches them for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, d, transactionHash, j, logIndex)); + i.second.changes.push_back(LocalisedLogEntry(l, d, transactionHash, j, logIndex, _polarity)); io_changed.insert(i.first); } } @@ -656,10 +656,10 @@ void Client::syncTransactionQueue() h->noteNewTransactions(); } -void Client::onChainChanged(ImportRoute const& _ir) +void Client::onDeadBlocks(h256s const& _blocks, h256Hash& io_changed) { // insert transactions that we are declaring the dead part of the chain - for (auto const& h: _ir.deadBlocks()) + for (auto const& h: _blocks) { clog(ClientNote) << "Dead block:" << h; for (auto const& t: m_bc.transactions(h)) @@ -669,8 +669,14 @@ void Client::onChainChanged(ImportRoute const& _ir) } } + for (auto const& h: _blocks) + appendFromBlock(h, false, io_changed); +} + +void Client::onNewBlocks(h256s const& _blocks, h256Hash& io_changed) +{ // remove transactions from m_tq nicely rather than relying on out of date nonce later on. - for (auto const& h: _ir.liveBlocks()) + for (auto const& h: _blocks) { clog(ClientChat) << "Live block:" << h; for (auto const& th: m_bc.transactionHashes(h)) @@ -683,12 +689,12 @@ void Client::onChainChanged(ImportRoute const& _ir) if (auto h = m_host.lock()) h->noteNewBlocks(); - h256Hash changeds; - for (auto const& h: _ir.liveBlocks()) - appendFromNewBlock(h, changeds); - - // RESTART MINING + for (auto const& h: _blocks) + appendFromBlock(h, true, io_changed); +} +void Client::restartMining() +{ bool preChanged = false; State newPreMine; DEV_READ_GUARDED(x_preMine) @@ -717,15 +723,20 @@ void Client::onChainChanged(ImportRoute const& _ir) DEV_READ_GUARDED(x_working) DEV_WRITE_GUARDED(x_postMine) m_postMine = m_working; - changeds.insert(PendingChangedFilter); - onPostStateChanged(); } +} + +void Client::onChainChanged(ImportRoute const& _ir) +{ + h256Hash changeds; + onDeadBlocks(_ir.deadBlocks(), changeds); + onNewBlocks(_ir.liveBlocks(), changeds); + restartMining(); // Quick hack for now - the TQ at this point already has the prior pending transactions in it; // we should resync with it manually until we are stricter about what constitutes "knowing". onTransactionQueueReady(); - noteChanged(changeds); } diff --git a/libethereum/Client.h b/libethereum/Client.h index cba93290b..13ef08b35 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -251,7 +251,7 @@ protected: /// Collate the changed filters for the hash of the given block. /// Insert any filters that are activated into @a o_changed. - void appendFromNewBlock(h256 const& _blockHash, h256Hash& io_changed); + void appendFromBlock(h256 const& _blockHash, bool _polarity, h256Hash& io_changed); /// Record that the set of filters @a _filters have changed. /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. @@ -270,6 +270,15 @@ private: /// Called when wouldMine(), turboMining(), isChainBad(), forceMining(), pendingTransactions() have changed. void rejigMining(); + /// Called on chain changes + void onDeadBlocks(h256s const& _blocks, h256Hash& io_changed); + + /// Called on chain changes + void onNewBlocks(h256s const& _blocks, h256Hash& io_changed); + + /// Called after processing blocks by onChainChanged(_ir) + void restartMining(); + /// Magically called when the chain has changed. An import route is provided. /// Called by either submitWork() or in our main thread through syncBlockQueue(). void onChainChanged(ImportRoute const& _ir); diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 357292853..24c55d816 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -75,8 +75,9 @@ struct LocalisedLogEntry: public LogEntry BlockInfo const& _bi, h256 _th, unsigned _ti, - unsigned _li - ): LogEntry(_le), blockHash(_bi.hash()), blockNumber((BlockNumber)_bi.number), transactionHash(_th), transactionIndex(_ti), logIndex(_li), mined(true) {}; + unsigned _li, + bool _polarity = true + ): LogEntry(_le), blockHash(_bi.hash()), blockNumber((BlockNumber)_bi.number), transactionHash(_th), transactionIndex(_ti), logIndex(_li), mined(true), polarity(_polarity) {}; h256 blockHash = h256(); BlockNumber blockNumber = 0; @@ -84,6 +85,7 @@ struct LocalisedLogEntry: public LogEntry unsigned transactionIndex = 0; unsigned logIndex = 0; bool mined = false; + bool polarity = true; h256 special = h256(); }; From e08fb98a32f32a585d9867ef0f31234ddc176d5e Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 14 Jun 2015 07:06:13 +0200 Subject: [PATCH 002/113] merge fix --- libethereum/Client.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 63633225f..7d967f669 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -741,6 +741,10 @@ void Client::restartMining() onPostStateChanged(); } + + // Quick hack for now - the TQ at this point already has the prior pending transactions in it; + // we should resync with it manually until we are stricter about what constitutes "knowing". + onTransactionQueueReady(); } } @@ -750,10 +754,6 @@ void Client::onChainChanged(ImportRoute const& _ir) onDeadBlocks(_ir.deadBlocks, changeds); onNewBlocks(_ir.liveBlocks, changeds); restartMining(); - - // Quick hack for now - the TQ at this point already has the prior pending transactions in it; - // we should resync with it manually until we are stricter about what constitutes "knowing". - onTransactionQueueReady(); noteChanged(changeds); } From f77325de18f040764ac35443d0b2452e7d1cfa86 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 14 Jun 2015 10:14:54 +0200 Subject: [PATCH 003/113] block polarity enum && jsonrpc field --- libethereum/BlockChain.h | 3 ++- libethereum/Client.cpp | 6 +++--- libethereum/Client.h | 2 +- libethereum/ClientBase.cpp | 2 +- libevm/ExtVMFace.h | 11 +++++++++-- libweb3jsonrpc/WebThreeStubServerBase.cpp | 3 +++ 6 files changed, 19 insertions(+), 8 deletions(-) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index e3fcf83c1..2d3abd922 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -81,7 +81,8 @@ using BlocksHash = std::unordered_map; using TransactionHashes = h256s; using UncleHashes = h256s; -struct ImportRoute { +struct ImportRoute +{ h256s deadBlocks; h256s liveBlocks; }; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 7d967f669..ea144c307 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -480,7 +480,7 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& } } -void Client::appendFromBlock(h256 const& _block, bool _polarity, h256Hash& io_changed) +void Client::appendFromBlock(h256 const& _block, BlockPolarity _polarity, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. auto d = m_bc.info(_block); @@ -682,7 +682,7 @@ void Client::onDeadBlocks(h256s const& _blocks, h256Hash& io_changed) } for (auto const& h: _blocks) - appendFromBlock(h, false, io_changed); + appendFromBlock(h, BlockPolarity::Dead, io_changed); } void Client::onNewBlocks(h256s const& _blocks, h256Hash& io_changed) @@ -702,7 +702,7 @@ void Client::onNewBlocks(h256s const& _blocks, h256Hash& io_changed) h->noteNewBlocks(); for (auto const& h: _blocks) - appendFromBlock(h, true, io_changed); + appendFromBlock(h, BlockPolarity::Live, io_changed); } void Client::restartMining() diff --git a/libethereum/Client.h b/libethereum/Client.h index eb05983b2..e25e8e0e4 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -251,7 +251,7 @@ protected: /// Collate the changed filters for the hash of the given block. /// Insert any filters that are activated into @a o_changed. - void appendFromBlock(h256 const& _blockHash, bool _polarity, h256Hash& io_changed); + void appendFromBlock(h256 const& _blockHash, BlockPolarity _polarity, h256Hash& io_changed); /// Record that the set of filters @a _filters have changed. /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index d5bc0dbb9..2b25599cb 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -217,7 +217,7 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { total += le.size(); for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], info, th, i, logIndex)); + ret.insert(ret.begin(), LocalisedLogEntry(le[j], info, th, i, logIndex, BlockPolarity::Live)); } } diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 24c55d816..2d65631e0 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -36,6 +36,13 @@ namespace dev namespace eth { +enum class BlockPolarity +{ + Unknown, + Dead, + Live +}; + struct LogEntry { LogEntry() {} @@ -76,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry h256 _th, unsigned _ti, unsigned _li, - bool _polarity = true + BlockPolarity _polarity = BlockPolarity::Unknown ): LogEntry(_le), blockHash(_bi.hash()), blockNumber((BlockNumber)_bi.number), transactionHash(_th), transactionIndex(_ti), logIndex(_li), mined(true), polarity(_polarity) {}; h256 blockHash = h256(); @@ -85,7 +92,7 @@ struct LocalisedLogEntry: public LogEntry unsigned transactionIndex = 0; unsigned logIndex = 0; bool mined = false; - bool polarity = true; + BlockPolarity polarity = BlockPolarity::Unknown; h256 special = h256(); }; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index f88443ee5..5bdd98e87 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -169,8 +169,11 @@ static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) res["data"] = toJS(_e.data); res["address"] = toJS(_e.address); res["topics"] = Json::Value(Json::arrayValue); + res["polarity"] = _e.polarity == BlockPolarity::Live ? true : false; + for (auto const& t: _e.topics) res["topics"].append(toJS(t)); + if (_e.mined) { res["type"] = "mined"; From d79569fb634c2d3340530c997c6cb733b949f4c7 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 04:24:50 +0200 Subject: [PATCH 004/113] eth_getFilterChangesEx, eth_getFilterLogsEx returns json in proper format --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 54 ++++++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 5bdd98e87..54568672e 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -198,6 +198,56 @@ static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) return res; } +static Json::Value toJsonEx(dev::eth::LocalisedLogEntries const& _es) +{ + map entriesByBlock; + + for (dev::eth::LocalisedLogEntry const& e: _es) + { + if (e.topics.size() == 0) // skip special log + continue; + + if (entriesByBlock.count(e.blockHash) == 0) + entriesByBlock[e.blockHash] = LocalisedLogEntries(); + + entriesByBlock[e.blockHash].push_back(e); + } + + Json::Value res(Json::arrayValue); + for (auto const& i: entriesByBlock) + { + Json::Value currentBlock(Json::objectValue); + LocalisedLogEntry entry = i.second[0]; + if (entry.mined) + { + + currentBlock["blockNumber"] = entry.blockNumber; + currentBlock["blockHash"] = toJS(entry.blockHash); + currentBlock["type"] = "mined"; + } + else + currentBlock["type"] = "pending"; + + currentBlock["logs"] = Json::Value(Json::arrayValue); + + for (LocalisedLogEntry const& e: i.second) + { + Json::Value log(Json::objectValue); + log["logIndex"] = e.logIndex; + log["polarity"] = e.polarity == BlockPolarity::Live ? true : false; + log["transactionIndex"] = e.transactionIndex; + log["transactionHash"] = toJS(e.transactionHash); + log["address"] = toJS(e.address); + log["data"] = toJS(e.data); + log["topics"] = toJS(e.topics); + + currentBlock["logs"].append(log); + } + + res.append(currentBlock); + } +} + static Json::Value toJson(dev::eth::LocalisedLogEntries const& _es) { Json::Value res(Json::arrayValue); @@ -1001,7 +1051,7 @@ Json::Value WebThreeStubServerBase::eth_getFilterChangesEx(string const& _filter auto entries = client()->checkWatch(id); if (entries.size()) cnote << "FIRING WATCH" << id << entries.size(); - return toJson(entries); + return toJsonEx(entries); } catch (...) { @@ -1025,7 +1075,7 @@ Json::Value WebThreeStubServerBase::eth_getFilterLogsEx(string const& _filterId) { try { - return toJson(client()->logs(jsToInt(_filterId))); + return toJsonEx(client()->logs(jsToInt(_filterId))); } catch (...) { From 7355368df1a3acd6c250f61c877d10eb4fec3f5d Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 04:50:26 +0200 Subject: [PATCH 005/113] missing return in toJsonEx --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 54568672e..f750ea692 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -246,6 +246,8 @@ static Json::Value toJsonEx(dev::eth::LocalisedLogEntries const& _es) res.append(currentBlock); } + + return res; } static Json::Value toJson(dev::eth::LocalisedLogEntries const& _es) From e98317f2dd44389ee0d716f079a75a68f6a5affa Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 24 Jun 2015 23:07:05 +0200 Subject: [PATCH 006/113] blockchain isKnown block / transaction --- libethereum/BlockChain.h | 3 +++ libethereum/ClientBase.cpp | 16 ++++++++++++++++ libethereum/ClientBase.h | 4 ++++ libethereum/Interface.h | 3 +++ libweb3jsonrpc/WebThreeStubServerBase.cpp | 14 ++++++++++---- libweb3jsonrpc/WebThreeStubServerBase.h | 4 ++-- libweb3jsonrpc/abstractwebthreestubserver.h | 8 ++++---- libweb3jsonrpc/spec.json | 4 ++-- test/libweb3jsonrpc/webthreestubclient.h | 12 ++++++------ 9 files changed, 50 insertions(+), 18 deletions(-) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index fc56c46b6..e97a0e7a3 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -184,6 +184,9 @@ public: std::vector withBlockBloom(LogBloom const& _b, unsigned _earliest, unsigned _latest) const; std::vector withBlockBloom(LogBloom const& _b, unsigned _earliest, unsigned _latest, unsigned _topLevel, unsigned _index) const; + /// Returns true if transaction is known. Thread-safe + bool isKnownTransaction(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); return !!ta; } + /// Get a transaction from its hash. Thread-safe. bytes transaction(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); } std::pair transactionLocation(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return std::pair(h256(), 0); return std::make_pair(ta.blockHash, ta.index); } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 2b25599cb..823bc6b35 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -467,3 +467,19 @@ int ClientBase::compareBlockHashes(h256 _h1, h256 _h2) const } return -1; } + +bool ClientBase::isKnown(h256 _hash) const +{ + return bc().isKnown(_hash); +} + +bool ClientBase::isKnown(BlockNumber _block) const +{ + return bc().numberHash(_block) != h256(); +} + +bool ClientBase::isKnownTransaction(h256 _transactionHash) const +{ + return bc().isKnownTransaction(_transactionHash); +} + diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 8aa84101c..e46bfe24d 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -148,6 +148,10 @@ public: /// Get the coinbase address virtual Address address() const override; + virtual bool isKnown(h256 _hash) const override; + virtual bool isKnown(BlockNumber _block) const override; + virtual bool isKnownTransaction(h256 _transactionHash) const override; + /// TODO: consider moving it to a separate interface virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); } diff --git a/libethereum/Interface.h b/libethereum/Interface.h index f631fb43e..204ce7dec 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -133,12 +133,15 @@ public: // [BLOCK QUERY API] + virtual bool isKnownTransaction(h256 _transactionHash) const = 0; virtual Transaction transaction(h256 _transactionHash) const = 0; virtual std::pair transactionLocation(h256 const& _transactionHash) const = 0; virtual h256 hashFromNumber(BlockNumber _number) const = 0; virtual BlockNumber numberFromHash(h256 _blockHash) const = 0; virtual int compareBlockHashes(h256 _h1, h256 _h2) const = 0; + virtual bool isKnown(BlockNumber _block) const = 0; + virtual bool isKnown(h256 _hash) const = 0; virtual BlockInfo blockInfo(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0; virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 0be37b6c6..b92b7ffc1 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -186,11 +186,14 @@ string WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const } } -string WebThreeStubServerBase::eth_getUncleCountByBlockHash(string const& _blockHash) +Json::Value WebThreeStubServerBase::eth_getUncleCountByBlockHash(string const& _blockHash) { try { - return toJS(client()->uncleCount(jsToFixed<32>(_blockHash))); + h256 blockHash = jsToFixed<32>(_blockHash); + if (!client()->isKnown(blockHash)) + return Json::Value(Json::nullValue); + return toJS(client()->uncleCount(blockHash)); } catch (...) { @@ -198,11 +201,14 @@ string WebThreeStubServerBase::eth_getUncleCountByBlockHash(string const& _block } } -string WebThreeStubServerBase::eth_getUncleCountByBlockNumber(string const& _blockNumber) +Json::Value WebThreeStubServerBase::eth_getUncleCountByBlockNumber(string const& _blockNumber) { try { - return toJS(client()->uncleCount(jsToBlockNumber(_blockNumber))); + BlockNumber blockNumber = jsToBlockNumber(_blockNumber); + if (!client()->isKnown(blockNumber)) + return Json::Value(Json::nullValue); + return toJS(client()->uncleCount(blockNumber)); } catch (...) { diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index d3e16d0f4..8e3de4c17 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -108,8 +108,8 @@ public: virtual std::string eth_getTransactionCount(std::string const& _address, std::string const& _blockNumber); virtual std::string eth_getBlockTransactionCountByHash(std::string const& _blockHash); virtual std::string eth_getBlockTransactionCountByNumber(std::string const& _blockNumber); - virtual std::string eth_getUncleCountByBlockHash(std::string const& _blockHash); - virtual std::string eth_getUncleCountByBlockNumber(std::string const& _blockNumber); + virtual Json::Value eth_getUncleCountByBlockHash(std::string const& _blockHash); + virtual Json::Value eth_getUncleCountByBlockNumber(std::string const& _blockNumber); virtual std::string eth_getCode(std::string const& _address, std::string const& _blockNumber); virtual std::string eth_sendTransaction(Json::Value const& _json); virtual std::string eth_call(Json::Value const& _json, std::string const& _blockNumber); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 82864a61a..20a248985 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -29,8 +29,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_getTransactionCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionCountI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByHashI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByNumberI); - this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockHashI); - this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockNumberI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockHashI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockNumberI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getCode", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getCodeI); this->bindAndAddMethod(jsonrpc::Procedure("eth_sendTransaction", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_sendTransactionI); this->bindAndAddMethod(jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_callI); @@ -478,8 +478,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("eth_getUncleCountByBlockHash",p); - if (result.isString()) - return result.asString(); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - std::string eth_getUncleCountByBlockNumber(const std::string& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_getUncleCountByBlockNumber(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); Json::Value result = this->CallMethod("eth_getUncleCountByBlockNumber",p); - if (result.isString()) - return result.asString(); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } From 0c239358775c0a06dc8bae237ac75f26a0dcada1 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 24 Jun 2015 23:25:13 +0200 Subject: [PATCH 007/113] getBlockBy** and getBlockTransactionCountBy** return null if block is not found --- libethereum/ClientBase.cpp | 9 +++++-- libweb3jsonrpc/WebThreeStubServerBase.cpp | 26 +++++++++++++++++---- libweb3jsonrpc/WebThreeStubServerBase.h | 4 ++-- libweb3jsonrpc/abstractwebthreestubserver.h | 8 +++---- libweb3jsonrpc/spec.json | 4 ++-- test/libweb3jsonrpc/webthreestubclient.h | 12 +++++----- 6 files changed, 42 insertions(+), 21 deletions(-) diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 823bc6b35..5f10267a6 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -470,12 +470,17 @@ int ClientBase::compareBlockHashes(h256 _h1, h256 _h2) const bool ClientBase::isKnown(h256 _hash) const { - return bc().isKnown(_hash); + return _hash == PendingBlockHash || + _hash == LatestBlockHash || + _hash == EarliestBlockHash || + bc().isKnown(_hash); } bool ClientBase::isKnown(BlockNumber _block) const { - return bc().numberHash(_block) != h256(); + return _block == PendingBlock || + _block == LatestBlock || + bc().numberHash(_block) != h256(); } bool ClientBase::isKnownTransaction(h256 _transactionHash) const diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index b92b7ffc1..fd740c74e 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -162,11 +162,15 @@ string WebThreeStubServerBase::eth_getTransactionCount(string const& _address, s } } -string WebThreeStubServerBase::eth_getBlockTransactionCountByHash(string const& _blockHash) +Json::Value WebThreeStubServerBase::eth_getBlockTransactionCountByHash(string const& _blockHash) { try { - return toJS(client()->transactionCount(jsToFixed<32>(_blockHash))); + h256 blockHash = jsToFixed<32>(_blockHash); + if (!client()->isKnown(blockHash)) + return Json::Value(Json::nullValue); + + return toJS(client()->transactionCount(blockHash)); } catch (...) { @@ -174,10 +178,14 @@ string WebThreeStubServerBase::eth_getBlockTransactionCountByHash(string const& } } -string WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const& _blockNumber) +Json::Value WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const& _blockNumber) { try { + BlockNumber blockNumber = jsToBlockNumber(_blockNumber); + if (!client()->isKnown(blockNumber)) + return Json::Value(Json::nullValue); + return toJS(client()->transactionCount(jsToBlockNumber(_blockNumber))); } catch (...) @@ -193,6 +201,7 @@ Json::Value WebThreeStubServerBase::eth_getUncleCountByBlockHash(string const& _ h256 blockHash = jsToFixed<32>(_blockHash); if (!client()->isKnown(blockHash)) return Json::Value(Json::nullValue); + return toJS(client()->uncleCount(blockHash)); } catch (...) @@ -208,6 +217,7 @@ Json::Value WebThreeStubServerBase::eth_getUncleCountByBlockNumber(string const& BlockNumber blockNumber = jsToBlockNumber(_blockNumber); if (!client()->isKnown(blockNumber)) return Json::Value(Json::nullValue); + return toJS(client()->uncleCount(blockNumber)); } catch (...) @@ -336,7 +346,10 @@ Json::Value WebThreeStubServerBase::eth_getBlockByHash(string const& _blockHash, { try { - auto h = jsToFixed<32>(_blockHash); + h256 h = jsToFixed<32>(_blockHash); + if (!client()->isKnown(h)) + return Json::Value(Json::nullValue); + if (_includeTransactions) return toJson(client()->blockInfo(h), client()->blockDetails(h), client()->uncleHashes(h), client()->transactions(h)); else @@ -352,7 +365,10 @@ Json::Value WebThreeStubServerBase::eth_getBlockByNumber(string const& _blockNum { try { - auto h = jsToBlockNumber(_blockNumber); + BlockNumber h = jsToBlockNumber(_blockNumber); + if (!client()->isKnown(h)) + return Json::Value(Json::nullValue); + if (_includeTransactions) return toJson(client()->blockInfo(h), client()->blockDetails(h), client()->uncleHashes(h), client()->transactions(h)); else diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 8e3de4c17..94fbd1acb 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -106,8 +106,8 @@ public: virtual std::string eth_getBalance(std::string const& _address, std::string const& _blockNumber); virtual std::string eth_getStorageAt(std::string const& _address, std::string const& _position, std::string const& _blockNumber); virtual std::string eth_getTransactionCount(std::string const& _address, std::string const& _blockNumber); - virtual std::string eth_getBlockTransactionCountByHash(std::string const& _blockHash); - virtual std::string eth_getBlockTransactionCountByNumber(std::string const& _blockNumber); + virtual Json::Value eth_getBlockTransactionCountByHash(std::string const& _blockHash); + virtual Json::Value eth_getBlockTransactionCountByNumber(std::string const& _blockNumber); virtual Json::Value eth_getUncleCountByBlockHash(std::string const& _blockHash); virtual Json::Value eth_getUncleCountByBlockNumber(std::string const& _blockNumber); virtual std::string eth_getCode(std::string const& _address, std::string const& _blockNumber); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 20a248985..6d0db7394 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -27,8 +27,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_getBalance", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBalanceI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getStorageAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getStorageAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getTransactionCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getTransactionCountI); - this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByHashI); - this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByNumberI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByHashI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getBlockTransactionCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getBlockTransactionCountByNumberI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockHashI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getUncleCountByBlockNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getUncleCountByBlockNumberI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getCode", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getCodeI); @@ -476,8 +476,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("eth_getBlockTransactionCountByHash",p); - if (result.isString()) - return result.asString(); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - std::string eth_getBlockTransactionCountByNumber(const std::string& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_getBlockTransactionCountByNumber(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); Json::Value result = this->CallMethod("eth_getBlockTransactionCountByNumber",p); - if (result.isString()) - return result.asString(); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } From 69230c59b7030ef28970618895ffd4dd0d0b648a Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 25 Jun 2015 09:51:22 +0200 Subject: [PATCH 008/113] fixed getting transaction by blockNumber and index --- libethereum/Interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 204ce7dec..1073b45ff 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -154,7 +154,7 @@ public: BlockInfo blockInfo(BlockNumber _block) const { return blockInfo(hashFromNumber(_block)); } BlockDetails blockDetails(BlockNumber _block) const { return blockDetails(hashFromNumber(_block)); } - Transaction transaction(BlockNumber _block, unsigned _i) const { if (_block == PendingBlock) { auto p = pending(); return _i < p.size() ? p[_i] : Transaction(); } return transaction(hashFromNumber(_block)); } + Transaction transaction(BlockNumber _block, unsigned _i) const { auto p = transactions(_block); return _i < p.size() ? p[_i] : Transaction(); } unsigned transactionCount(BlockNumber _block) const { if (_block == PendingBlock) { auto p = pending(); return p.size(); } return transactionCount(hashFromNumber(_block)); } Transactions transactions(BlockNumber _block) const { if (_block == PendingBlock) return pending(); return transactions(hashFromNumber(_block)); } TransactionHashes transactionHashes(BlockNumber _block) const { if (_block == PendingBlock) return pendingHashes(); return transactionHashes(hashFromNumber(_block)); } From 51c705e3d398d0bf62ed1583297f70f306a87c84 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 25 Jun 2015 10:08:01 +0200 Subject: [PATCH 009/113] fixed eth_getTransactionByHash when transactionHash is unknown --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index fd740c74e..bbf8ec225 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -385,6 +385,9 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByHash(string const& _tran try { h256 h = jsToFixed<32>(_transactionHash); + if (!client()->isKnownTransaction(h)) + return Json::Value(Json::nullValue); + auto l = client()->transactionLocation(h); return toJson(client()->transaction(h), l, client()->numberFromHash(l.first)); } From 5c64ba8aae74722d95a961c9092253ec20c87c35 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 25 Jun 2015 11:19:16 +0200 Subject: [PATCH 010/113] fixed encoding unformatted data in eth_getStorageAt --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index bbf8ec225..4e4d42469 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -142,7 +142,7 @@ string WebThreeStubServerBase::eth_getStorageAt(string const& _address, string c { try { - return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_position), jsToBlockNumber(_blockNumber))); + return toJS(toCompactBigEndian(client()->stateAt(jsToAddress(_address), jsToU256(_position), jsToBlockNumber(_blockNumber)), 1)); } catch (...) { From 4ec30f961e438417f813fa3874ceb83542730207 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 7 Jul 2015 18:57:39 +0200 Subject: [PATCH 011/113] LocalisedTransaction && LocalisedTransactionReceipt --- libethereum/Client.cpp | 2 +- libethereum/ClientBase.cpp | 2 +- libethereum/Transaction.h | 24 ++++++++++++++++ libethereum/TransactionReceipt.h | 48 ++++++++++++++++++++++++++++++++ libevm/ExtVMFace.h | 19 +++++++------ 5 files changed, 84 insertions(+), 11 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index fba8d51fa..db4578285 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -429,7 +429,7 @@ void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) auto transactionHash = transaction(d.hash(), j).sha3(); // filter catches them for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, d, transactionHash, j, logIndex)); + i.second.changes.push_back(LocalisedLogEntry(l, d.hash(), (BlockNumber)d.number, transactionHash, j, logIndex)); io_changed.insert(i.first); } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 2cef62680..6483f6c0c 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -203,7 +203,7 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { total += le.size(); for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], info, th, i, logIndex)); + ret.insert(ret.begin(), LocalisedLogEntry(le[j], info.hash(), (BlockNumber)info.number, th, i, logIndex)); } } diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 8ed0043c9..d29e9837e 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -130,5 +130,29 @@ private: /// Nice name for vector of Transaction. using Transactions = std::vector; +class LocalisedTransaction: public Transaction +{ +public: + LocalisedTransaction( + Transaction const& _t, + std::pair const& _location, + BlockNumber _blockNumber + ): + Transaction(_t), + m_blockHash(_location.first), + m_blockNumber(_blockNumber), + m_transactionIndex(_location.second) + {} + + h256 const& blockHash() const { return m_blockHash; } + BlockNumber blockNumber() const { return m_blockNumber; } + unsigned transactionIndex() const { return m_transactionIndex; } + +private: + h256 m_blockHash; + BlockNumber m_blockNumber; + unsigned m_transactionIndex; +}; + } } diff --git a/libethereum/TransactionReceipt.h b/libethereum/TransactionReceipt.h index 0a0b154f4..8c102611a 100644 --- a/libethereum/TransactionReceipt.h +++ b/libethereum/TransactionReceipt.h @@ -58,5 +58,53 @@ using TransactionReceipts = std::vector; std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r); +class LocalisedTransactionReceipt: public TransactionReceipt +{ +public: + LocalisedTransactionReceipt( + TransactionReceipt const& _t, + h256 const& _hash, + h256 const& _blockHash, + BlockNumber _blockNumber, + unsigned _transactionIndex, + Address const& _contractAddress = Address() + ): + TransactionReceipt(_t), + m_hash(_hash), + m_blockHash(_blockHash), + m_blockNumber(_blockNumber), + m_transactionIndex(_transactionIndex), + m_contractAddress(_contractAddress) + {} + + h256 const& hash() const { return m_hash; } + h256 const& blockHash() const { return m_blockHash; } + BlockNumber blockNumber() const { return m_blockNumber; } + unsigned transactionIndex() const { return m_transactionIndex; } + Address const& contractAddress() const { return m_contractAddress; } + + LocalisedLogEntries localisedLogs() const + { + LocalisedLogEntries localisedEntries; + LogEntries entries = log(); + for (unsigned i = 0; i < entries.size(); i++) + localisedEntries.push_back(LocalisedLogEntry( + entries[i], + m_blockHash, + m_blockNumber, + m_hash, + m_transactionIndex, + i)); + return localisedEntries; + }; + +private: + h256 m_hash; + h256 m_blockHash; + BlockNumber m_blockNumber; + unsigned m_transactionIndex; + Address m_contractAddress; +}; + } } diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..6b40b4101 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -76,17 +76,18 @@ struct LocalisedLogEntry: public LogEntry explicit LocalisedLogEntry( LogEntry const& _le, - BlockInfo const& _bi, - h256 _th, - unsigned _ti, - unsigned _li + h256 const& _blockHash, + BlockNumber _blockNumber, + h256 const& _transactionHash, + unsigned _transactionIndex, + unsigned _logIndex ): LogEntry(_le), - blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), - transactionHash(_th), - transactionIndex(_ti), - logIndex(_li), + blockHash(_blockHash), + blockNumber(_blockNumber), + transactionHash(_transactionHash), + transactionIndex(_transactionIndex), + logIndex(_logIndex), mined(true) {} From e961867fdfa87ac78f1e69ad76768b5741a29f35 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 8 Jul 2015 10:09:29 +0200 Subject: [PATCH 012/113] LocalisedTransactionReceipt in ClientBase and WebThreeStubServerBase --- libethereum/BlockChain.h | 5 +++- libethereum/ClientBase.cpp | 14 ++++++++++ libethereum/ClientBase.h | 1 + libethereum/Interface.h | 1 + libethereum/TransactionReceipt.h | 28 ++++++++++---------- libweb3jsonrpc/JsonHelper.cpp | 31 +++++++---------------- libweb3jsonrpc/JsonHelper.h | 3 +-- libweb3jsonrpc/WebThreeStubServerBase.cpp | 3 +-- 8 files changed, 44 insertions(+), 42 deletions(-) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 4cffca2df..987d605ce 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -142,8 +142,11 @@ public: BlockReceipts receipts(h256 const& _hash) const { return queryExtras(_hash, m_receipts, x_receipts, NullBlockReceipts); } BlockReceipts receipts() const { return receipts(currentHash()); } + /// Get the transaction by block hash and index; + TransactionReceipt transactionReceipt(h256 const& _blockHash, unsigned _i) const {return receipts(_blockHash).receipts[_i]; } + /// Get the transaction receipt by transaction hash. Thread-safe. - TransactionReceipt transactionReceipt(h256 const& _transactionHash) const {TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return receipts(ta.blockHash).receipts[ta.index]; } + TransactionReceipt transactionReceipt(h256 const& _transactionHash) const {TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return transactionReceipt(ta.blockHash, ta.index); } /// Get a list of transaction hashes for a given block. Thread-safe. TransactionHashes transactionHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 6483f6c0c..66ecfc2b4 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -332,6 +332,20 @@ TransactionReceipt ClientBase::transactionReceipt(h256 const& _transactionHash) return bc().transactionReceipt(_transactionHash); } +LocalisedTransactionReceipt ClientBase::localisedTransactionReceipt(h256 const& _transactionHash) const +{ + std::pair tl = bc().transactionLocation(_transactionHash); + Transaction t = Transaction(bc().transaction(tl.first, tl.second), CheckTransaction::Cheap); + TransactionReceipt tr = bc().transactionReceipt(tl.first, tl.second); + return LocalisedTransactionReceipt( + tr, + t.sha3(), + tl.first, + numberFromHash(tl.first), + tl.second, + toAddress(t.from(), t.nonce())); +} + pair ClientBase::transactionLocation(h256 const& _transactionHash) const { return bc().transactionLocation(_transactionHash); diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 05766b3a1..e8795abd2 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -120,6 +120,7 @@ public: virtual Transaction transaction(h256 _transactionHash) const override; virtual Transaction transaction(h256 _blockHash, unsigned _i) const override; virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const override; + virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const override; virtual std::pair transactionLocation(h256 const& _transactionHash) const override; virtual Transactions transactions(h256 _blockHash) const override; virtual TransactionHashes transactionHashes(h256 _blockHash) const override; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index c65670a30..07758851c 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -136,6 +136,7 @@ public: virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0; virtual Transaction transaction(h256 _transactionHash) const = 0; virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const = 0; + virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const = 0; virtual std::pair transactionLocation(h256 const& _transactionHash) const = 0; virtual h256 hashFromNumber(BlockNumber _number) const = 0; virtual BlockNumber numberFromHash(h256 _blockHash) const = 0; diff --git a/libethereum/TransactionReceipt.h b/libethereum/TransactionReceipt.h index 8c102611a..ceb1123b5 100644 --- a/libethereum/TransactionReceipt.h +++ b/libethereum/TransactionReceipt.h @@ -75,35 +75,33 @@ public: m_blockNumber(_blockNumber), m_transactionIndex(_transactionIndex), m_contractAddress(_contractAddress) - {} - - h256 const& hash() const { return m_hash; } - h256 const& blockHash() const { return m_blockHash; } - BlockNumber blockNumber() const { return m_blockNumber; } - unsigned transactionIndex() const { return m_transactionIndex; } - Address const& contractAddress() const { return m_contractAddress; } - - LocalisedLogEntries localisedLogs() const { - LocalisedLogEntries localisedEntries; LogEntries entries = log(); for (unsigned i = 0; i < entries.size(); i++) - localisedEntries.push_back(LocalisedLogEntry( + m_localisedLogs.push_back(LocalisedLogEntry( entries[i], m_blockHash, m_blockNumber, m_hash, m_transactionIndex, - i)); - return localisedEntries; - }; + i + )); + } + + h256 const& hash() const { return m_hash; } + h256 const& blockHash() const { return m_blockHash; } + BlockNumber blockNumber() const { return m_blockNumber; } + unsigned transactionIndex() const { return m_transactionIndex; } + Address const& contractAddress() const { return m_contractAddress; } + LocalisedLogEntries const& localisedLogs() const { return m_localisedLogs; }; private: h256 m_hash; h256 m_blockHash; BlockNumber m_blockNumber; - unsigned m_transactionIndex; + unsigned m_transactionIndex = 0; Address m_contractAddress; + LocalisedLogEntries m_localisedLogs; }; } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..34ab5ad7f 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -182,30 +182,17 @@ Json::Value toJson(dev::eth::TransactionReceipt const& _t) return res; } -Json::Value toJson(dev::eth::TransactionReceipt const& _tr, std::pair _location, BlockNumber _blockNumber, Transaction const& _t) +Json::Value toJson(dev::eth::LocalisedTransactionReceipt const& _t) { Json::Value res; - h256 h = _t.sha3(); - res["transactionHash"] = toJS(h); - res["transactionIndex"] = _location.second; - res["blockHash"] = toJS(_location.first); - res["blockNumber"] = _blockNumber; - res["cumulativeGasUsed"] = toJS(_tr.gasUsed()); // TODO: check if this is fine - res["gasUsed"] = toJS(_tr.gasUsed()); - res["contractAddress"] = toJS(toAddress(_t.from(), _t.nonce())); - res["logs"] = Json::Value(Json::arrayValue); - for (unsigned i = 0; i < _tr.log().size(); i++) - { - LogEntry e = _tr.log()[i]; - Json::Value l = toJson(e); - l["type"] = "mined"; - l["blockNumber"] = _blockNumber; - l["blockHash"] = toJS(_location.first); - l["logIndex"] = i; - l["transactionHash"] = toJS(h); - l["transactionIndex"] = _location.second; - res["logs"].append(l); - } + res["transactionHash"] = toJS(_t.hash()); + res["transactionIndex"] = _t.transactionIndex(); + res["blockHash"] = toJS(_t.blockHash()); + res["blockNumber"] = _t.blockNumber(); + res["cumulativeGasUsed"] = toJS(_t.gasUsed()); // TODO: check if this is fine + res["gasUsed"] = toJS(_t.gasUsed()); + res["contractAddress"] = toJS(_t.contractAddress()); + res["logs"] = dev::toJson(_t.localisedLogs()); return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..8e42cf77a 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -57,8 +57,7 @@ Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes co Json::Value toJson(TransactionSkeleton const& _t); Json::Value toJson(Transaction const& _t); Json::Value toJson(TransactionReceipt const& _t); -//TODO: wrap these params into one structure eg. "LocalisedTransactionReceipt" -Json::Value toJson(TransactionReceipt const& _tr, std::pair _location, BlockNumber _blockNumber, Transaction const& _t); +Json::Value toJson(LocalisedTransactionReceipt const& _t); Json::Value toJson(LocalisedLogEntry const& _e); Json::Value toJson(LogEntry const& _e); TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..fd1555161 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -427,8 +427,7 @@ Json::Value WebThreeStubServerBase::eth_getTransactionReceipt(string const& _tra if (!client()->isKnownTransaction(h)) return Json::Value(Json::nullValue); - auto l = client()->transactionLocation(h); - return toJson(client()->transactionReceipt(h), l, client()->numberFromHash(l.first), client()->transaction(h)); + return toJson(client()->localisedTransactionReceipt(h)); } catch (...) { From 7beb78413ce98c38f5d20984adca97f95a8a8b39 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 8 Jul 2015 10:40:54 +0200 Subject: [PATCH 013/113] LocalisedTransaction in ClientBase and WebThreeStubServerBase --- libethereum/ClientBase.cpp | 12 ++++++++++++ libethereum/ClientBase.h | 2 ++ libethereum/Interface.h | 2 ++ libethereum/Transaction.h | 9 +++++---- libweb3jsonrpc/JsonHelper.cpp | 20 ++++++++++++++++++++ libweb3jsonrpc/JsonHelper.h | 2 ++ libweb3jsonrpc/WebThreeStubServerBase.cpp | 9 +++------ 7 files changed, 46 insertions(+), 10 deletions(-) diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 66ecfc2b4..141556411 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -317,6 +317,12 @@ Transaction ClientBase::transaction(h256 _transactionHash) const return Transaction(bc().transaction(_transactionHash), CheckTransaction::Cheap); } +LocalisedTransaction ClientBase::localisedTransaction(h256 _transactionHash) const +{ + std::pair tl = bc().transactionLocation(_transactionHash); + return localisedTransaction(tl.first, tl.second); +} + Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const { auto bl = bc().block(_blockHash); @@ -327,6 +333,12 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const return Transaction(); } +LocalisedTransaction ClientBase::localisedTransaction(h256 _blockHash, unsigned _i) const +{ + Transaction t = Transaction(bc().transaction(_blockHash, _i), CheckTransaction::Cheap); + return LocalisedTransaction(t, _blockHash, numberFromHash(_blockHash), _i); +} + TransactionReceipt ClientBase::transactionReceipt(h256 const& _transactionHash) const { return bc().transactionReceipt(_transactionHash); diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index e8795abd2..d0fbb4151 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -118,7 +118,9 @@ public: virtual BlockInfo blockInfo(h256 _hash) const override; virtual BlockDetails blockDetails(h256 _hash) const override; virtual Transaction transaction(h256 _transactionHash) const override; + virtual LocalisedTransaction localisedTransaction(h256 _transactionHash) const override; virtual Transaction transaction(h256 _blockHash, unsigned _i) const override; + virtual LocalisedTransaction localisedTransaction(h256 _blockHash, unsigned _i) const override; virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const override; virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const override; virtual std::pair transactionLocation(h256 const& _transactionHash) const override; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 07758851c..0f1c5f2a3 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -135,6 +135,7 @@ public: virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0; virtual Transaction transaction(h256 _transactionHash) const = 0; + virtual LocalisedTransaction localisedTransaction(h256 _transactionHash) const = 0; virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const = 0; virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const = 0; virtual std::pair transactionLocation(h256 const& _transactionHash) const = 0; @@ -147,6 +148,7 @@ public: virtual BlockInfo blockInfo(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0; virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; + virtual LocalisedTransaction localisedTransaction(h256 _blockHash, unsigned _i) const = 0; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0; virtual UncleHashes uncleHashes(h256 _blockHash) const = 0; virtual unsigned transactionCount(h256 _blockHash) const = 0; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index d29e9837e..2332a6fdb 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -135,13 +135,14 @@ class LocalisedTransaction: public Transaction public: LocalisedTransaction( Transaction const& _t, - std::pair const& _location, - BlockNumber _blockNumber + h256 const& _blockHash, + BlockNumber _blockNumber, + unsigned _transactionIndex ): Transaction(_t), - m_blockHash(_location.first), + m_blockHash(_blockHash), m_blockNumber(_blockNumber), - m_transactionIndex(_location.second) + m_transactionIndex(_transactionIndex) {} h256 const& blockHash() const { return m_blockHash; } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 34ab5ad7f..ab976eddd 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -214,6 +214,26 @@ Json::Value toJson(dev::eth::Transaction const& _t) return res; } +Json::Value toJson(dev::eth::LocalisedTransaction const& _t) +{ + Json::Value res; + if (_t) + { + res["hash"] = toJS(_t.sha3()); + res["input"] = toJS(_t.data()); + res["to"] = _t.isCreation() ? Json::Value() : toJS(_t.receiveAddress()); + res["from"] = toJS(_t.safeSender()); + res["gas"] = toJS(_t.gas()); + res["gasPrice"] = toJS(_t.gasPrice()); + res["nonce"] = toJS(_t.nonce()); + res["value"] = toJS(_t.value()); + res["blockHash"] = toJS(_t.blockHash()); + res["transactionIndex"] = toJS(_t.transactionIndex()); + res["blockNumber"] = toJS(_t.blockNumber()); + } + return res; +} + Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) { Json::Value res; diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 8e42cf77a..3c652db7a 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -43,6 +43,7 @@ namespace eth { class Transaction; +class LocalisedTransaction; struct BlockDetails; class Interface; using Transactions = std::vector; @@ -56,6 +57,7 @@ Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes co Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, TransactionHashes const& _ts); Json::Value toJson(TransactionSkeleton const& _t); Json::Value toJson(Transaction const& _t); +Json::Value toJson(LocalisedTransaction const& _t); Json::Value toJson(TransactionReceipt const& _t); Json::Value toJson(LocalisedTransactionReceipt const& _t); Json::Value toJson(LocalisedLogEntry const& _e); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index fd1555161..f91d29ea7 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -380,8 +380,7 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByHash(string const& _tran if (!client()->isKnownTransaction(h)) return Json::Value(Json::nullValue); - auto l = client()->transactionLocation(h); - return toJson(client()->transaction(h), l, client()->numberFromHash(l.first)); + return toJson(client()->localisedTransaction(h)); } catch (...) { @@ -395,8 +394,7 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockHashAndIndex(string { h256 bh = jsToFixed<32>(_blockHash); unsigned ti = jsToInt(_transactionIndex); - Transaction t = client()->transaction(bh, ti); - return toJson(t, make_pair(bh, ti), client()->numberFromHash(bh)); + return toJson(client()->localisedTransaction(bh, ti)); } catch (...) { @@ -410,8 +408,7 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockNumberAndIndex(stri { BlockNumber bn = jsToBlockNumber(_blockNumber); unsigned ti = jsToInt(_transactionIndex); - Transaction t = client()->transaction(bn, ti); - return toJson(t, make_pair(client()->hashFromNumber(bn), ti), bn); + return toJson(client()->localisedTransaction(client()->hashFromNumber(bn), ti)); } catch (...) { From a5e31dc4e754a18784e27e4caba6c55db8318b3f Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 8 Jul 2015 10:45:41 +0200 Subject: [PATCH 014/113] style fixes --- libethereum/Transaction.h | 2 +- libethereum/TransactionReceipt.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 2332a6fdb..b13630f6a 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -137,7 +137,7 @@ public: Transaction const& _t, h256 const& _blockHash, BlockNumber _blockNumber, - unsigned _transactionIndex + unsigned _transactionIndex ): Transaction(_t), m_blockHash(_blockHash), diff --git a/libethereum/TransactionReceipt.h b/libethereum/TransactionReceipt.h index ceb1123b5..6043cc5ee 100644 --- a/libethereum/TransactionReceipt.h +++ b/libethereum/TransactionReceipt.h @@ -63,11 +63,11 @@ class LocalisedTransactionReceipt: public TransactionReceipt public: LocalisedTransactionReceipt( TransactionReceipt const& _t, - h256 const& _hash, - h256 const& _blockHash, - BlockNumber _blockNumber, - unsigned _transactionIndex, - Address const& _contractAddress = Address() + h256 const& _hash, + h256 const& _blockHash, + BlockNumber _blockNumber, + unsigned _transactionIndex, + Address const& _contractAddress = Address() ): TransactionReceipt(_t), m_hash(_hash), From 596a2deaf6cfc1f293ae67ab39f1b09d77c5aada Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 9 Jul 2015 00:47:16 +0200 Subject: [PATCH 015/113] fixed style issues --- libethereum/BlockChain.h | 4 ++-- libethereum/ClientBase.cpp | 4 ++-- libethereum/ClientBase.h | 4 ++-- libethereum/Interface.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 9956226f2..ecaaee4c0 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -143,10 +143,10 @@ public: BlockReceipts receipts() const { return receipts(currentHash()); } /// Get the transaction by block hash and index; - TransactionReceipt transactionReceipt(h256 const& _blockHash, unsigned _i) const {return receipts(_blockHash).receipts[_i]; } + TransactionReceipt transactionReceipt(h256 const& _blockHash, unsigned _i) const { return receipts(_blockHash).receipts[_i]; } /// Get the transaction receipt by transaction hash. Thread-safe. - TransactionReceipt transactionReceipt(h256 const& _transactionHash) const {TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return transactionReceipt(ta.blockHash, ta.index); } + TransactionReceipt transactionReceipt(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return transactionReceipt(ta.blockHash, ta.index); } /// Get a list of transaction hashes for a given block. Thread-safe. TransactionHashes transactionHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 5a5f89b72..5d5af7c6b 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -317,7 +317,7 @@ Transaction ClientBase::transaction(h256 _transactionHash) const return Transaction(bc().transaction(_transactionHash), CheckTransaction::Cheap); } -LocalisedTransaction ClientBase::localisedTransaction(h256 _transactionHash) const +LocalisedTransaction ClientBase::localisedTransaction(h256 const& _transactionHash) const { std::pair tl = bc().transactionLocation(_transactionHash); return localisedTransaction(tl.first, tl.second); @@ -333,7 +333,7 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const return Transaction(); } -LocalisedTransaction ClientBase::localisedTransaction(h256 _blockHash, unsigned _i) const +LocalisedTransaction ClientBase::localisedTransaction(h256 const& _blockHash, unsigned _i) const { Transaction t = Transaction(bc().transaction(_blockHash, _i), CheckTransaction::Cheap); return LocalisedTransaction(t, _blockHash, numberFromHash(_blockHash), _i); diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 31a0f7499..91a9daf29 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -118,9 +118,9 @@ public: virtual BlockInfo blockInfo(h256 _hash) const override; virtual BlockDetails blockDetails(h256 _hash) const override; virtual Transaction transaction(h256 _transactionHash) const override; - virtual LocalisedTransaction localisedTransaction(h256 _transactionHash) const override; + virtual LocalisedTransaction localisedTransaction(h256 const& _transactionHash) const override; virtual Transaction transaction(h256 _blockHash, unsigned _i) const override; - virtual LocalisedTransaction localisedTransaction(h256 _blockHash, unsigned _i) const override; + virtual LocalisedTransaction localisedTransaction(h256 const& _blockHash, unsigned _i) const override; virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const override; virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const override; virtual std::pair transactionLocation(h256 const& _transactionHash) const override; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index d030e666f..418b8e0ff 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -135,7 +135,7 @@ public: virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0; virtual Transaction transaction(h256 _transactionHash) const = 0; - virtual LocalisedTransaction localisedTransaction(h256 _transactionHash) const = 0; + virtual LocalisedTransaction localisedTransaction(h256 const& _transactionHash) const = 0; virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const = 0; virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const = 0; virtual std::pair transactionLocation(h256 const& _transactionHash) const = 0; @@ -148,7 +148,7 @@ public: virtual BlockInfo blockInfo(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0; virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; - virtual LocalisedTransaction localisedTransaction(h256 _blockHash, unsigned _i) const = 0; + virtual LocalisedTransaction localisedTransaction(h256 const& _blockHash, unsigned _i) const = 0; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0; virtual UncleHashes uncleHashes(h256 _blockHash) const = 0; virtual unsigned transactionCount(h256 _blockHash) const = 0; From c6371bec4921b47009b95d93bac64554f7fce5fb Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 9 Jul 2015 00:59:32 +0200 Subject: [PATCH 016/113] blockNumber is optional for LocalisedTransaction --- libethereum/ClientBase.cpp | 2 +- libethereum/Transaction.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 5d5af7c6b..b133e3731 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -336,7 +336,7 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const LocalisedTransaction ClientBase::localisedTransaction(h256 const& _blockHash, unsigned _i) const { Transaction t = Transaction(bc().transaction(_blockHash, _i), CheckTransaction::Cheap); - return LocalisedTransaction(t, _blockHash, numberFromHash(_blockHash), _i); + return LocalisedTransaction(t, _blockHash, _i, numberFromHash(_blockHash)); } TransactionReceipt ClientBase::transactionReceipt(h256 const& _transactionHash) const diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index b13630f6a..02373fe9e 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -136,23 +136,23 @@ public: LocalisedTransaction( Transaction const& _t, h256 const& _blockHash, - BlockNumber _blockNumber, - unsigned _transactionIndex + unsigned _transactionIndex, + BlockNumber _blockNumber = 0 ): Transaction(_t), m_blockHash(_blockHash), - m_blockNumber(_blockNumber), - m_transactionIndex(_transactionIndex) + m_transactionIndex(_transactionIndex), + m_blockNumber(_blockNumber) {} h256 const& blockHash() const { return m_blockHash; } - BlockNumber blockNumber() const { return m_blockNumber; } unsigned transactionIndex() const { return m_transactionIndex; } + BlockNumber blockNumber() const { return m_blockNumber; } private: h256 m_blockHash; - BlockNumber m_blockNumber; unsigned m_transactionIndex; + BlockNumber m_blockNumber; }; } From f6719db60fba03f3b0626e76f98e3eec97f0e922 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Jul 2015 00:32:04 +0200 Subject: [PATCH 017/113] commit eth_getFilterLogs returns reverted logs --- libethereum/Client.cpp | 7 ++--- libethereum/ClientBase.cpp | 58 ++++++++++++++++++-------------------- libethereum/ClientBase.h | 1 + 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 42b5bbcf4..b485f7def 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -412,7 +412,6 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromBlock(h256 const& _block, BlockPolarity _polarity, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); auto receipts = m_bc.receipts(_block).receipts; Guard l(x_filtersWatches); @@ -421,18 +420,16 @@ void Client::appendFromBlock(h256 const& _block, BlockPolarity _polarity, h256Ha for (pair& i: m_filters) { // acceptable number & looks like block may contain a matching log entry. - unsigned logIndex = 0; for (size_t j = 0; j < receipts.size(); j++) { - logIndex++; auto tr = receipts[j]; auto m = i.second.filter.matches(tr); if (m.size()) { - auto transactionHash = transaction(d.hash(), j).sha3(); + auto transactionHash = transaction(_block, j).sha3(); // filter catches them for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, d.hash(), (BlockNumber)d.number, transactionHash, j, logIndex, _polarity)); + i.second.changes.push_back(LocalisedLogEntry(l, _block, (BlockNumber)bc().number(_block), transactionHash, j, 0, _polarity)); io_changed.insert(i.first); } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 375fd74f7..440443156 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -171,49 +171,47 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const // Might have a transaction that contains a matching log. TransactionReceipt const& tr = temp.receipt(i); LogEntries le = _f.matches(tr); - if (le.size()) - for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j])); + for (unsigned j = 0; j < le.size(); ++j) + ret.insert(ret.begin(), LocalisedLogEntry(le[j])); } begin = bc().number(); } - + + // Handle blocks from main chain set matchingBlocks; for (auto const& i: _f.bloomPossibilities()) for (auto u: bc().withBlockBloom(i, end, begin)) matchingBlocks.insert(u); - unsigned falsePos = 0; for (auto n: matchingBlocks) + appendLogsFromBlock(_f, bc().numberHash(n), BlockPolarity::Live, ret); + + // Handle reverted blocks + h256s blocks; + h256 ancestor; + unsigned ancestorIndex; + tie(blocks, ancestor, ancestorIndex) = bc().treeRoute(_f.earliest(), _f.latest(), false); + + for (size_t i = 0; i < ancestorIndex; i++) + appendLogsFromBlock(_f, blocks[i], BlockPolarity::Dead, ret); + + return ret; +} + +void ClientBase::appendLogsFromBlock(LogFilter const& _f, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const +{ + auto receipts = bc().receipts(_blockHash).receipts; + for (size_t i = 0; i < receipts.size(); i++) { - int total = 0; - auto h = bc().numberHash(n); - auto info = bc().info(h); - auto receipts = bc().receipts(h).receipts; - unsigned logIndex = 0; - for (size_t i = 0; i < receipts.size(); i++) + TransactionReceipt receipt = receipts[i]; + if (_f.matches(receipt.bloom())) { - logIndex++; - TransactionReceipt receipt = receipts[i]; - if (_f.matches(receipt.bloom())) - { - auto th = transaction(info.hash(), i).sha3(); - LogEntries le = _f.matches(receipt); - if (le.size()) - { - total += le.size(); - for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], info.hash(), (BlockNumber)info.number, th, i, logIndex, BlockPolarity::Live)); - } - } - - if (!total) - falsePos++; + auto th = transaction(_blockHash, i).sha3(); + LogEntries le = _f.matches(receipt); + for (unsigned j = 0; j < le.size(); ++j) + io_logs.insert(io_logs.begin(), LocalisedLogEntry(le[j], _blockHash, (BlockNumber)bc().number(_blockHash), th, i, 0, _polarity)); } } - - cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves"; - return ret; } unsigned ClientBase::installWatch(LogFilter const& _f, Reaping _r) diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 91a9daf29..b68fc540f 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -104,6 +104,7 @@ public: virtual LocalisedLogEntries logs(unsigned _watchId) const override; virtual LocalisedLogEntries logs(LogFilter const& _filter) const override; + virtual void appendLogsFromBlock(LogFilter const& _filter, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const; /// Install, uninstall and query watches. virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override; From a72b51c86dc3105672e8b3f8370087af83d32ae4 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 15 Jul 2015 01:11:32 +0200 Subject: [PATCH 018/113] clear reverted block hashes from cache during imporing --- libethereum/BlockChain.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index d9a54a1ee..b6890d160 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -597,10 +597,27 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Most of the time these two will be equal - only when we're doing a chain revert will they not be if (common != last) + { // If we are reverting previous blocks, we need to clear their blooms (in particular, to // rebuild any higher level blooms that they contributed to). clearBlockBlooms(number(common) + 1, number(last) + 1); + // clear reverted blockhashes + DEV_WRITE_GUARDED(x_blockHashes) + for (auto i = route.begin(); i != route.end() && *i != common; ++i) + { + BlockInfo tbi = BlockInfo(block(*i)); + auto h = h256(tbi.number); + for (auto j = m_blockHashes.begin(); j != m_blockHashes.end();) + { + if (j->first == h) + j = m_blockHashes.erase(j); + else + ++j; + } + } + } + // Go through ret backwards until hash != last.parent and update m_transactionAddresses, m_blockHashes for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i) { From 358f9b49cd06366dac4b5073057df357a5baa234 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 15 Jul 2015 10:31:32 +0200 Subject: [PATCH 019/113] eth_getTransactionByBlockHash && eth_getTransactionByBlockNumber returns null when transactions are out of scope --- libethereum/ClientBase.cpp | 4 ++++ libethereum/ClientBase.h | 1 + libethereum/Interface.h | 1 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 9 ++++++++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 440443156..4f913304d 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -503,3 +503,7 @@ bool ClientBase::isKnownTransaction(h256 const& _transactionHash) const return bc().isKnownTransaction(_transactionHash); } +bool ClientBase::isKnownTransaction(h256 const& _blockHash, unsigned _i) const +{ + return isKnown(_blockHash) && bc().transactions().size() > _i; +} diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index b68fc540f..9e513124a 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -152,6 +152,7 @@ public: virtual bool isKnown(h256 const& _hash) const override; virtual bool isKnown(BlockNumber _block) const override; virtual bool isKnownTransaction(h256 const& _transactionHash) const override; + virtual bool isKnownTransaction(h256 const& _blockHash, unsigned _i) const override; /// TODO: consider moving it to a separate interface diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 418b8e0ff..753b712ea 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -134,6 +134,7 @@ public: // [BLOCK QUERY API] virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0; + virtual bool isKnownTransaction(h256 const& _blockHash, unsigned _i) const = 0; virtual Transaction transaction(h256 _transactionHash) const = 0; virtual LocalisedTransaction localisedTransaction(h256 const& _transactionHash) const = 0; virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const = 0; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index a9d74d3ac..8b1962941 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -394,6 +394,9 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockHashAndIndex(string { h256 bh = jsToFixed<32>(_blockHash); unsigned ti = jsToInt(_transactionIndex); + if (!client()->isKnownTransaction(bh, ti)) + return Json::Value(Json::nullValue); + return toJson(client()->localisedTransaction(bh, ti)); } catch (...) @@ -407,8 +410,12 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockNumberAndIndex(stri try { BlockNumber bn = jsToBlockNumber(_blockNumber); + h256 bh = client()->hashFromNumber(bn); unsigned ti = jsToInt(_transactionIndex); - return toJson(client()->localisedTransaction(client()->hashFromNumber(bn), ti)); + if (!client()->isKnownTransaction(bh, ti)) + return Json::Value(Json::nullValue); + + return toJson(client()->localisedTransaction(bh, ti)); } catch (...) { From 2344e14f1bbbe56b628ef61fc945ff71c3cbdb50 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 15 Jul 2015 12:00:28 +0200 Subject: [PATCH 020/113] proper combinatorics in LogFilter::bloomPossibilities(), #2295 --- libethereum/LogFilter.cpp | 55 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/libethereum/LogFilter.cpp b/libethereum/LogFilter.cpp index 6e0fbd709..029869c7a 100644 --- a/libethereum/LogFilter.cpp +++ b/libethereum/LogFilter.cpp @@ -77,9 +77,58 @@ vector LogFilter::bloomPossibilities() const { // return combination of each of the addresses/topics vector ret; - // TODO proper combinatorics. - for (auto i: m_addresses) - ret.push_back(LogBloom().shiftBloom<3>(dev::sha3(i))); + + // | every address with every topic + for (auto const& i: m_addresses) + { + // 1st case, there are addresses and topics + // + // m_addresses = [a0, a1]; + // m_topics = [[t0], [t1a, t1b], [], []]; + // + // blooms = [ + // a0 | t0, a0 | t1a | t1b, + // a1 | t0, a1 | t1a | t1b + // ] + // + for (auto const& t: m_topics) + if (t.size()) + { + LogBloom b = LogBloom().shiftBloom<3>(dev::sha3(i)); + for (auto const &j: t) + b = b.shiftBloom<3>(dev::sha3(j)); + ret.push_back(b); + } + } + + // 2nd case, there are no topics + // + // m_addresses = [a0, a1]; + // m_topics = [[t0], [t1a, t1b], [], []]; + // + // blooms = [a0, a1]; + // + if (!ret.size()) + for (auto const& i: m_addresses) + ret.push_back(LogBloom().shiftBloom<3>(dev::sha3(i))); + + // 3rd case, there are no addresses, at least create blooms from topics + // + // m_addresses = []; + // m_topics = [[t0], [t1a, t1b], [], []]; + // + // blooms = [t0, t1a | t1b]; + // + if (!m_addresses.size()) + for (auto const& t: m_topics) + if (t.size()) + { + LogBloom b; + for (auto const &j: t) + b = b.shiftBloom<3>(dev::sha3(j)); + ret.push_back(b); + } + return ret; } From d692c959c79d47a3f37feebb70ee4c0d8c7c41ec Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 15 Jul 2015 12:26:04 +0200 Subject: [PATCH 021/113] fixed anonymous logs --- libethereum/ClientBase.cpp | 49 +++++++++++++++++++++++++------------- libethereum/LogFilter.cpp | 16 +++++++++++++ libethereum/LogFilter.h | 10 ++++++++ 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 4f913304d..fb81c2592 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -177,16 +177,8 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const begin = bc().number(); } - // Handle blocks from main chain - set matchingBlocks; - for (auto const& i: _f.bloomPossibilities()) - for (auto u: bc().withBlockBloom(i, end, begin)) - matchingBlocks.insert(u); - - for (auto n: matchingBlocks) - appendLogsFromBlock(_f, bc().numberHash(n), BlockPolarity::Live, ret); - // Handle reverted blocks + // There are not so many, so let's iterate over them h256s blocks; h256 ancestor; unsigned ancestorIndex; @@ -195,6 +187,34 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const for (size_t i = 0; i < ancestorIndex; i++) appendLogsFromBlock(_f, blocks[i], BlockPolarity::Dead, ret); + // cause end is our earliest block, let's compare it with our ancestor + // if ancestor is smaller let's move our end to it + // example: + // + // 3b -> 2b -> 1b + // -> g + // 3a -> 2a -> 1a + // + // if earliest is at 1a and latest is a 3b, coverting them to numbers + // will give us pair (1, 3) + // and we want to get all logs from g (ancestor) to 3 + // so we have to move 1a to g + end = min(end, (unsigned)numberFromHash(ancestor)); + + // Handle blocks from main chain + set matchingBlocks; + if (!_f.isRangeFilter()) + for (auto const& i: _f.bloomPossibilities()) + for (auto u: bc().withBlockBloom(i, end, begin)) + matchingBlocks.insert(u); + else + // if it is a range filter, we want to get all logs from all blocks in given range + for (unsigned i = end; i <= begin; i++) + matchingBlocks.insert(i); + + for (auto n: matchingBlocks) + appendLogsFromBlock(_f, bc().numberHash(n), BlockPolarity::Live, ret); + return ret; } @@ -204,13 +224,10 @@ void ClientBase::appendLogsFromBlock(LogFilter const& _f, h256 const& _blockHash for (size_t i = 0; i < receipts.size(); i++) { TransactionReceipt receipt = receipts[i]; - if (_f.matches(receipt.bloom())) - { - auto th = transaction(_blockHash, i).sha3(); - LogEntries le = _f.matches(receipt); - for (unsigned j = 0; j < le.size(); ++j) - io_logs.insert(io_logs.begin(), LocalisedLogEntry(le[j], _blockHash, (BlockNumber)bc().number(_blockHash), th, i, 0, _polarity)); - } + auto th = transaction(_blockHash, i).sha3(); + LogEntries le = _f.matches(receipt); + for (unsigned j = 0; j < le.size(); ++j) + io_logs.insert(io_logs.begin(), LocalisedLogEntry(le[j], _blockHash, (BlockNumber)bc().number(_blockHash), th, i, 0, _polarity)); } } diff --git a/libethereum/LogFilter.cpp b/libethereum/LogFilter.cpp index 029869c7a..95c07f2a3 100644 --- a/libethereum/LogFilter.cpp +++ b/libethereum/LogFilter.cpp @@ -46,6 +46,18 @@ h256 LogFilter::sha3() const return dev::sha3(s.out()); } +bool LogFilter::isRangeFilter() const +{ + if (m_addresses.size()) + return false; + + for (auto const& t: m_topics) + if (t.size()) + return false; + + return true; +} + bool LogFilter::matches(LogBloom _bloom) const { if (m_addresses.size()) @@ -134,6 +146,10 @@ vector LogFilter::bloomPossibilities() const LogEntries LogFilter::matches(TransactionReceipt const& _m) const { + // there are no addresses or topics to filter + if (isRangeFilter()) + return _m.log(); + LogEntries ret; if (matches(_m.bloom())) for (LogEntry const& e: _m.log()) diff --git a/libethereum/LogFilter.h b/libethereum/LogFilter.h index ff33346f8..092f173ef 100644 --- a/libethereum/LogFilter.h +++ b/libethereum/LogFilter.h @@ -50,10 +50,20 @@ public: void streamRLP(RLPStream& _s) const; h256 sha3() const; + /// hash of earliest block which should be filtered h256 earliest() const { return m_earliest; } + + /// hash of latest block which should be filtered h256 latest() const { return m_latest; } + /// Range filter is a filter which doesn't care about addresses or topics + /// Matches are all entries from earliest to latest + /// @returns true if addresses and topics are unspecified + bool isRangeFilter() const; + + /// @returns bloom possibilities for all addresses and topics std::vector bloomPossibilities() const; + bool matches(LogBloom _bloom) const; bool matches(State const& _s, unsigned _i) const; LogEntries matches(TransactionReceipt const& _r) const; From ad884353915db593364732a62ed8c56493599159 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 15 Jul 2015 13:35:19 +0200 Subject: [PATCH 022/113] logs are being returned in proper order, without ancestor --- libethereum/ClientBase.cpp | 17 +++++++++-------- libethereum/ClientBase.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index fb81c2592..9ac9d9647 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -185,7 +185,7 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const tie(blocks, ancestor, ancestorIndex) = bc().treeRoute(_f.earliest(), _f.latest(), false); for (size_t i = 0; i < ancestorIndex; i++) - appendLogsFromBlock(_f, blocks[i], BlockPolarity::Dead, ret); + prependLogsFromBlock(_f, blocks[i], BlockPolarity::Dead, ret); // cause end is our earliest block, let's compare it with our ancestor // if ancestor is smaller let's move our end to it @@ -195,11 +195,11 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const // -> g // 3a -> 2a -> 1a // - // if earliest is at 1a and latest is a 3b, coverting them to numbers - // will give us pair (1, 3) - // and we want to get all logs from g (ancestor) to 3 - // so we have to move 1a to g - end = min(end, (unsigned)numberFromHash(ancestor)); + // if earliest is at 2a and latest is a 3b, coverting them to numbers + // will give us pair (2, 3) + // and we want to get all logs from 1 (ancestor + 1) to 3 + // so we have to move 2a to g + 1 + end = min(end, (unsigned)numberFromHash(ancestor) + 1); // Handle blocks from main chain set matchingBlocks; @@ -213,12 +213,13 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const matchingBlocks.insert(i); for (auto n: matchingBlocks) - appendLogsFromBlock(_f, bc().numberHash(n), BlockPolarity::Live, ret); + prependLogsFromBlock(_f, bc().numberHash(n), BlockPolarity::Live, ret); + reverse(ret.begin(), ret.end()); return ret; } -void ClientBase::appendLogsFromBlock(LogFilter const& _f, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const +void ClientBase::prependLogsFromBlock(LogFilter const& _f, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const { auto receipts = bc().receipts(_blockHash).receipts; for (size_t i = 0; i < receipts.size(); i++) diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 9e513124a..2b762c0b4 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -104,7 +104,7 @@ public: virtual LocalisedLogEntries logs(unsigned _watchId) const override; virtual LocalisedLogEntries logs(LogFilter const& _filter) const override; - virtual void appendLogsFromBlock(LogFilter const& _filter, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const; + virtual void prependLogsFromBlock(LogFilter const& _filter, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const; /// Install, uninstall and query watches. virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override; From 2ff5f57355e016bee7ff2de0d97bc8bfd6c6f181 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 15 Jul 2015 17:18:34 +0200 Subject: [PATCH 023/113] getLogsEx && propert order of returned Ex logs --- libweb3jsonrpc/JsonHelper.cpp | 23 ++++++++++++++------- libweb3jsonrpc/JsonHelper.h | 2 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 14 ++++++++++++- libweb3jsonrpc/WebThreeStubServerBase.h | 1 + libweb3jsonrpc/abstractwebthreestubserver.h | 6 ++++++ libweb3jsonrpc/spec.json | 1 + test/libweb3jsonrpc/webthreestubclient.h | 10 +++++++++ 7 files changed, 47 insertions(+), 10 deletions(-) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 10bd50ea3..9ffb1db0d 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -277,13 +277,14 @@ Json::Value toJson(dev::eth::LogEntry const& _e) return res; } -Json::Value toJson(std::map const& _entriesByBlock) +Json::Value toJson(std::unordered_map const& _entriesByBlock, vector const& _order) { Json::Value res(Json::arrayValue); - for (auto const& i: _entriesByBlock) + for (auto const& i: _order) { + auto entries = _entriesByBlock.at(i); Json::Value currentBlock(Json::objectValue); - LocalisedLogEntry entry = i.second[0]; + LocalisedLogEntry entry = entries[0]; if (entry.mined) { @@ -294,18 +295,20 @@ Json::Value toJson(std::map const& _entries else currentBlock["type"] = "pending"; + currentBlock["polarity"] = entry.polarity == BlockPolarity::Live ? true : false; currentBlock["logs"] = Json::Value(Json::arrayValue); - for (LocalisedLogEntry const& e: i.second) + for (LocalisedLogEntry const& e: entries) { Json::Value log(Json::objectValue); log["logIndex"] = e.logIndex; - log["polarity"] = e.polarity == BlockPolarity::Live ? true : false; log["transactionIndex"] = e.transactionIndex; log["transactionHash"] = toJS(e.transactionHash); log["address"] = toJS(e.address); log["data"] = toJS(e.data); - log["topics"] = toJS(e.topics); + log["topics"] = Json::Value(Json::arrayValue); + for (auto const& t: e.topics) + log["topics"].append(toJS(t)); currentBlock["logs"].append(log); } @@ -318,7 +321,8 @@ Json::Value toJson(std::map const& _entries Json::Value toJsonByBlock(LocalisedLogEntries const& _entries) { - map entriesByBlock; + vector order; + unordered_map entriesByBlock; for (dev::eth::LocalisedLogEntry const& e: _entries) { @@ -326,12 +330,15 @@ Json::Value toJsonByBlock(LocalisedLogEntries const& _entries) continue; if (entriesByBlock.count(e.blockHash) == 0) + { entriesByBlock[e.blockHash] = LocalisedLogEntries(); + order.push_back(e.blockHash); + } entriesByBlock[e.blockHash].push_back(e); } - return toJson(entriesByBlock); + return toJson(entriesByBlock, order); } TransactionSkeleton toTransactionSkeleton(Json::Value const& _json) diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 1cf633a2f..a5688d763 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -62,7 +62,7 @@ Json::Value toJson(TransactionReceipt const& _t); Json::Value toJson(LocalisedTransactionReceipt const& _t); Json::Value toJson(LocalisedLogEntry const& _e); Json::Value toJson(LogEntry const& _e); -Json::Value toJson(std::map const& _entriesByBlock); +Json::Value toJson(std::unordered_map const& _entriesByBlock); Json::Value toJsonByBlock(LocalisedLogEntries const& _entries); TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 8b1962941..a223c37d4 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -725,7 +725,19 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) { try { - return toJson(client()->logs(toLogFilter(_json))); + return toJson(client()->logs(toLogFilter(_json, *client()))); + } + catch (...) + { + BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); + } +} + +Json::Value WebThreeStubServerBase::eth_getLogsEx(Json::Value const& _json) +{ + try + { + return toJsonByBlock(client()->logs(toLogFilter(_json))); } catch (...) { diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index d90015aec..62209a5b4 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -136,6 +136,7 @@ public: virtual Json::Value eth_getFilterLogs(std::string const& _filterId); virtual Json::Value eth_getFilterLogsEx(std::string const& _filterId); virtual Json::Value eth_getLogs(Json::Value const& _json); + virtual Json::Value eth_getLogsEx(Json::Value const& _json); virtual Json::Value eth_getWork(); virtual bool eth_submitWork(std::string const& _nonce, std::string const&, std::string const& _mixHash); virtual std::string eth_register(std::string const& _address); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 988271c95..48421b940 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -57,6 +57,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogsEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsExI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_getLogsI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getLogsEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_getLogsExI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI); this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI); this->bindAndAddMethod(jsonrpc::Procedure("eth_register", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_registerI); @@ -296,6 +297,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_getLogs(request[0u]); } + inline virtual void eth_getLogsExI(const Json::Value &request, Json::Value &response) + { + response = this->eth_getLogsEx(request[0u]); + } inline virtual void eth_getWorkI(const Json::Value &request, Json::Value &response) { (void)request; @@ -511,6 +516,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("eth_getLogsEx",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } Json::Value eth_getWork() throw (jsonrpc::JsonRpcException) { Json::Value p; From 9ae950d4ad42a2610887f3738b8d21cf953e278d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jul 2015 18:59:19 -0700 Subject: [PATCH 024/113] Modularise nonce, mix hash and seed hash. --- alethzero/MainWin.cpp | 4 +-- ethminer/MinerAux.h | 10 +++---- exp/main.cpp | 2 +- libethcore/BlockInfo.cpp | 45 +++++++++++++----------------- libethcore/BlockInfo.h | 26 +++++++++--------- libethcore/Common.cpp | 5 ++-- libethcore/Common.h | 1 + libethcore/Ethash.cpp | 52 ++++++++++++++++++++++++++++------- libethcore/Ethash.h | 16 +++++++++-- libethcore/EthashAux.cpp | 7 ++++- libethcore/EthashAux.h | 2 +- libethcore/ProofOfWork.h | 1 - libethereum/BlockChain.cpp | 8 +++--- libethereum/BlockQueue.cpp | 12 ++++---- libethereum/State.cpp | 8 +++--- libethereum/State.h | 4 +-- libweb3jsonrpc/JsonHelper.cpp | 7 +++-- mix/MixClient.cpp | 1 - test/TestHelper.cpp | 2 +- 19 files changed, 128 insertions(+), 85 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e48b58283..4655240e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1718,7 +1718,7 @@ void Main::on_blocks_currentItemChanged() s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { @@ -1749,7 +1749,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ff28132b1..5c6112743 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -254,17 +254,17 @@ public: bi.difficulty = u256(m); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bi.proof.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; exit(0); } catch (...) @@ -382,7 +382,7 @@ private: { BlockInfo bi; bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/exp/main.cpp b/exp/main.cpp index 88608f8cf..9884bd0e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -197,7 +197,7 @@ int main() bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, bi); + bi.proof = sol; return completed = true; }); f.setWork(bi); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index fec5b4678..c7acd9091 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -26,7 +26,6 @@ #include #include #include "EthashAux.h" -#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -57,22 +56,21 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - mixHash = h256(); - nonce = Nonce(); - m_hash = m_seedHash = h256(); + proof = ProofOfWork::Solution(); + m_proofCache = ProofOfWork::HeaderCache(); + m_hash = h256(); } -h256 const& BlockInfo::seedHash() const +ProofOfWork::HeaderCache const& BlockInfo::proofCache() const { - if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); - return m_seedHash; + ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); + return m_proofCache; } h256 const& BlockInfo::hash() const { if (!m_hash) - m_hash = headerHash(WithNonce); + m_hash = headerHash(WithProof); return m_hash; } @@ -90,20 +88,20 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const return ret; } -h256 BlockInfo::headerHash(IncludeNonce _n) const +h256 BlockInfo::headerHash(IncludeProof _n) const { RLPStream s; streamRLP(s, _n); return sha3(s.out()); } -void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const +void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const { - _s.appendList(_n == WithNonce ? 15 : 13) + _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithNonce) - _s << mixHash << nonce; + if (_n == WithProof) + proof.streamRLP(_s); } h256 BlockInfo::headerHash(bytesConstRef _block) @@ -116,12 +114,12 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); - m_seedHash = h256(); + m_proofCache = ProofOfWork::HeaderCache(); int field = 0; try { - if (_header.itemCount() != 15) + if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); @@ -136,8 +134,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - mixHash = _header[field = 13].toHash(RLP::VeryStrict); - nonce = _header[field = 14].toHash(RLP::VeryStrict); + proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -152,22 +149,18 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ProofOfWork::composeException(ex, *this); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); - ex << errinfo_seedHash(seedHash()); ex << errinfo_target(boundary()); - ex << errinfo_mixHash(mixHash); - Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce); - ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); BOOST_THROW_EXCEPTION(ex); } else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); + ProofOfWork::composeExceptionPre(ex, *this); BOOST_THROW_EXCEPTION(ex); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 79c12ebb4..b77c47c6b 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -24,16 +24,17 @@ #include #include #include "Common.h" +#include "ProofOfWork.h" namespace dev { namespace eth { -enum IncludeNonce +enum IncludeProof { - WithoutNonce = 0, - WithNonce = 1 + WithoutProof = 0, + WithProof = 1 }; enum Strictness @@ -82,8 +83,7 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - h256 mixHash; - Nonce nonce; + typename ProofOfWork::Solution proof; BlockInfo(); explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} @@ -112,14 +112,13 @@ public: gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && extraData == _cmp.extraData && - mixHash == _cmp.mixHash && - nonce == _cmp.nonce; + proof == _cmp.proof; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } void clear(); - void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); } + void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); @@ -130,16 +129,17 @@ public: u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - h256 const& seedHash() const; + ProofOfWork::HeaderCache const& proofCache() const; h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeNonce _n) const; - void streamRLP(RLPStream& _s, IncludeNonce _n) const; + h256 headerHash(IncludeProof _n) const; + void streamRLP(RLPStream& _s, IncludeProof _n) const; private: - mutable h256 m_seedHash; + + mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; @@ -148,7 +148,7 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; + _bi.gasUsed << " " << _bi.timestamp; return _out; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 618703e22..41cd1bba8 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -26,6 +26,7 @@ #include #include "Exceptions.h" #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -112,9 +113,9 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset; string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; - string const c_space = c_border + string(76, ' ') + c_border; + string const c_space = c_border + string(76, ' ') + c_border + EthReset; stringstream ss; ss << c_line << endl; ss << c_space << endl; diff --git a/libethcore/Common.h b/libethcore/Common.h index 296f0d01d..1e0cdc3b1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -189,6 +189,7 @@ struct TransactionSkeleton Address to; u256 value; bytes data; + u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; u256 nonce = UndefinedU256; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9be76926d..6a4a1445f 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -46,6 +46,7 @@ #endif #include "BlockInfo.h" #include "EthashAux.h" +#include "Exceptions.h" using namespace std; using namespace std::chrono; @@ -56,6 +57,26 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); +void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +{ + if (!io_out) + io_out = EthashAux::seedHash((unsigned)_h.number); +} + +void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); + _ex << errinfo_mixHash(_bi.proof.mixHash); + _ex << errinfo_seedHash(_bi.proofCache()); + Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); + _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +} + +void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); +} + std::string Ethash::name() { return "Ethash"; @@ -66,12 +87,23 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) +{ + mixHash = _header[_field].toHash(RLP::VeryStrict); + nonce = _header[++_field].toHash(RLP::VeryStrict); +} + +void Ethash::Solution::streamRLP(RLPStream& io_rlp) const +{ + io_rlp << mixHash << nonce; +} + Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutNonce); - ret.seedHash = _bi.seedHash(); + ret.headerHash = _bi.headerHash(WithoutProof); + ret.seedHash = _bi.proofCache(); return ret; } @@ -84,7 +116,7 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { - EthashAux::full(_header.seedHash(), true, _f); + EthashAux::full(_header.proofCache(), true, _f); } bool Ethash::preVerify(BlockInfo const& _header) @@ -95,9 +127,9 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), + (uint64_t)(u64)_header.proof.nonce, + (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); return ret; @@ -115,7 +147,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -125,9 +157,9 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; + cwarn << "headerHash:" << _header.headerHash(WithoutProof); + cwarn << "nonce:" << _header.proof.nonce; + cwarn << "mixHash:" << _header.proof.mixHash; cwarn << "difficulty:" << _header.difficulty; cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 7ffd887d0..5640152f0 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -28,16 +28,20 @@ #include #include #include "Common.h" -#include "BlockInfo.h" #include "Miner.h" class ethash_cl_miner; namespace dev { + +class RLP; +class RLPStream; + namespace eth { +class BlockInfo; class EthashCLHook; class Ethash @@ -45,8 +49,17 @@ class Ethash public: using Miner = GenericMiner; + using HeaderCache = h256; + static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); + static void composeException(Exception& _ex, BlockInfo& _bi); + static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + struct Solution { + bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } + void populateFromRLP(RLP const& io_rlp, int& io_field); + void streamRLP(RLPStream& io_rlp) const; + static const unsigned Fields = 2; Nonce nonce; h256 mixHash; }; @@ -78,7 +91,6 @@ public: static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } class CPUMiner: public Miner, Worker { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index efb6066f7..db01f3c49 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,6 +200,11 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } +Ethash::Result EthashAux::eval(BlockInfo const& _header) +{ + return eval(_header, _header.proof.nonce); +} + #define DEV_IF_THROWS(X) try { X; } catch (...) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) @@ -252,7 +257,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { - return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); + return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index d5bd60d44..be07f579c 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -78,7 +78,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 764207aef..7b4298047 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -38,7 +38,6 @@ namespace eth * typename Solution * typename CPUMiner * typename GPUMiner - * void assignResult(BlockInfo&, Result) * and a few others. TODO */ using ProofOfWork = Ethash; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 768ed223f..aaafe7ce9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -575,8 +575,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash.abridged() @@ -666,8 +666,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f95a3880e..690fb60ee 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.hash; + bi.proof.mixHash = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.mixHash == work.hash) + if (it->verified.info.proof.mixHash == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.mixHash == work.hash) + if (i.verified.info.proof.mixHash == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..bf55a50ff 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -837,7 +837,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); + m_currentBlock.streamRLP(block, WithProof); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -902,7 +902,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithNonce); + ubi.streamRLP(unclesData, WithProof); ++unclesCount; uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) @@ -970,7 +970,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithNonce); + m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -978,7 +978,7 @@ void State::completeMine() cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.nonce.abridged(), + m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() ); diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..0555b6dcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -169,11 +169,11 @@ public: if (!m_committedToMine) return false; - PoW::assignResult(_result, m_currentBlock); + m_currentBlock.proof = _result; if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..f7c09ebc2 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -99,11 +99,12 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["gasLimit"] = toJS(_bi.gasLimit); res["timestamp"] = toJS(_bi.timestamp); res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); res["logsBloom"] = toJS(_bi.logBloom); - - res["seedHash"] = toJS(_bi.seedHash()); res["target"] = toJS(_bi.boundary()); + + // TODO: move into ProofOfWork. + res["nonce"] = toJS(_bi.proof.nonce); + res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 8373c7c51..ea4686601 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -49,7 +49,6 @@ namespace struct MixPow //dummy POW { typedef int Solution; - static void assignResult(int, BlockInfo const&) {} static bool verify(BlockInfo const&) { return true; } }; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f49ed1e09..b43c4db51 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(BlockInfo& _bi) bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, _bi); + _bi.proof = sol; return completed = true; }); f.setWork(_bi); From 212d4333701e51b497d1850ad82fd60da5ae6f4a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 13:03:52 -0700 Subject: [PATCH 025/113] Basic Proof-of-Authority sealent. --- eth/main.cpp | 3 + ethminer/MinerAux.h | 28 +++++++-- libdevcrypto/Common.cpp | 5 ++ libdevcrypto/Common.h | 3 + libethcore/Common.cpp | 4 ++ libethcore/Common.h | 13 +++- libethcore/Ethash.cpp | 26 +++++++- libethcore/Ethash.h | 31 +++++++++ libethcore/EthashAux.cpp | 11 ++++ libethcore/EthashAux.h | 1 + libethcore/Farm.h | 1 - libethcore/Miner.h | 11 ---- libethcore/ProofOfWork.cpp | 25 ++++++++ libethcore/ProofOfWork.h | 76 ++++++++++++++++++++++- libethereum/BlockChain.cpp | 4 ++ libethereum/BlockQueue.cpp | 12 ++-- libethereum/Client.cpp | 15 +---- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 +- libethereum/State.h | 2 +- libweb3jsonrpc/JsonHelper.cpp | 2 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 10 ++- 22 files changed, 246 insertions(+), 43 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 67058a473..1e724c7e6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1702,7 +1702,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) { From 5660a17ffed4e052ade82bfd04a5fffa1971f752 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH 026/113] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + 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 BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + 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 BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - 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); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) 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)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); - _ex << errinfo_mixHash(_bi.proof.mixHash); - _ex << errinfo_seedHash(_bi.proofCache()); - Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); - _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); -#else - (void)_ex; - (void)_bi; -#endif -} - -void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) -{ -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); -#else - (void)_ex; - (void)_bi; -#endif -} - -std::string Ethash::name() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) -{ - WorkPackage ret; - ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutProof); -#if ETH_USING_ETHASH - ret.seedHash = _bi.proofCache(); -#endif - return ret; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -void Ethash::prep(BlockInfo const& _header, std::function const& _f) -{ -#if ETH_USING_ETHASH - EthashAux::full(_header.proofCache(), true, _f); -#else - (void)_header; - (void)_f; -#endif + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (number >= ETHASH_EPOCH_LENGTH * 2048) return false; -#if ETH_USING_ETHASH - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ bool Ethash::verify(BlockInfo const& _header) } #endif -#if ETH_USING_ETHASH - auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + 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, unsigned, 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 + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - 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, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#else - using GPUMiner = CPUMiner; -#endif /// Default value of the local work size. Also known as workgroup size. static const unsigned defaultLocalWorkSize; /// Default value of the global work size as a multiplier of the local work size static const unsigned defaultGlobalWorkSizeMultiplier; /// Default value of the milliseconds per global work size (per batch) static const unsigned defaultMSPerBatch; - - struct Farm: public eth::GenericFarm - { - public: - strings sealers() const { return { "cpu", "opencl" }; } - void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } - - void sealBlock(BlockInfo const& _bi) - { - setWork(_bi); - if (m_opencl) - startGPU(); - else - startCPU(); - - setWork(_bi); - ensurePrecomputed((unsigned)_bi.number); - } - - void disable() { stop(); } - - private: - bool m_opencl = false; - }; }; } diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) - return true; - m_miners.clear(); - m_miners.reserve(MinerType::instances()); - for (unsigned i = 0; i < MinerType::instances(); ++i) - { - m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); - -bool BasicAuthority::verify(BlockInfo const& _header) -{ - return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; -} - -bool BasicAuthority::preVerify(BlockInfo const& _header) -{ - return SignatureStruct(_header.proof.sig).isValid(); -} - -BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) -{ - return WorkPackage{_header.headerHash(WithoutProof)}; -} - -void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) -{ - m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); -} - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -class BasicAuthority -{ -public: - struct HeaderCache {}; - static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} - static void composeException(Exception&, BlockInfo&) {} - static void composeExceptionPre(Exception&, BlockInfo&) {} - - struct Solution - { - bool operator==(Solution const& _v) const { return sig == _v.sig; } - void populateFromRLP(RLP const& io_rlp, int& io_field) - { - sig = io_rlp[io_field++].toHash(RLP::VeryStrict); - } - - void streamRLP(RLPStream& io_rlp) const - { - io_rlp << sig; - } - static const unsigned Fields = 1; - Signature sig; - }; - - struct Result - { - Signature sig; - }; - - struct WorkPackage - { - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } - - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - }; - - static const WorkPackage NullWorkPackage; - - static std::string name() { return "BasicAuthority"; } - static unsigned revision() { return 0; } - static void prep(BlockInfo const&, std::function const& = std::function()) {} - static void ensurePrecomputed(unsigned) {} - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - static const Address Authority; - - struct Farm - { - public: - strings sealers() const { return { "default" }; } - void setSealer(std::string const&) {} - void setSecret(Secret const& _s) { m_secret = _s; } - void sealBlock(BlockInfo const& _bi); - void disable() {} - void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } - - private: - Secret m_secret; - std::function m_onSolutionFound; - }; -}; - using ProofOfWork = BasicAuthority; } diff --git a/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + 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 Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + 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 Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady; From 4302afdf2cbeade79409c29d08aa4961e2bee7d3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Jul 2015 16:32:04 -0700 Subject: [PATCH 027/113] Tests working for BasicAuthority and Ethash. --- CMakeLists.txt | 32 ++++++++++++++-------------- exp/CMakeLists.txt | 20 ++++++++++++------ exp/main.cpp | 40 ++++++++++++++++++++++++++--------- libdevcore/Common.h | 1 + libethcore/BasicAuthority.cpp | 18 +++++++++++++--- libethcore/BasicAuthority.h | 7 +++++- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 1 + libethcore/EthashAux.cpp | 23 -------------------- libethcore/EthashAux.h | 2 -- libethcore/Sealer.h | 12 +++++++++++ 12 files changed, 97 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 271f3ed65..a75b612c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) - add_subdirectory(libweb3jsonrpc) +# add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) - add_subdirectory(libjsengine) - add_subdirectory(libjsconsole) - add_subdirectory(ethconsole) +# add_subdirectory(libjsengine) +# add_subdirectory(libjsconsole) +# add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -432,33 +432,33 @@ endif () add_subdirectory(libethcore) if (GENERAL) - add_subdirectory(libevm) - add_subdirectory(libethereum) - add_subdirectory(libwebthree) +# add_subdirectory(libevm) +# add_subdirectory(libethereum) +# add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) - add_subdirectory(ethminer) +# add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) - add_subdirectory(ethkey) +# add_subdirectory(ethkey) endif () if (TESTS) - add_subdirectory(libtestutils) - add_subdirectory(test) +# add_subdirectory(libtestutils) +# add_subdirectory(test) if (JSONRPC) - add_subdirectory(ethrpctest) +# add_subdirectory(ethrpctest) endif () endif () if (TOOLS) - add_subdirectory(rlp) - add_subdirectory(abi) - add_subdirectory(ethvm) - add_subdirectory(eth) +# add_subdirectory(rlp) +# add_subdirectory(abi) +# add_subdirectory(ethvm) +# add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index e6360317f..fc8611ad7 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -21,15 +21,21 @@ if (READLINE_FOUND) endif() if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) +# target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} p2p) +#target_link_libraries(${EXECUTABLE} webthree) +#target_link_libraries(${EXECUTABLE} ethereum) +#target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} ethash) - target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} ethash-cl) +# target_link_libraries(${EXECUTABLE} ethash) +# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) endif() +target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) + + + + + diff --git a/exp/main.cpp b/exp/main.cpp index 07eee6a11..fa8603459 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,6 +70,7 @@ namespace fs = boost::filesystem; #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -80,24 +81,43 @@ using namespace eth; int main() { BlockInfo bi; + bi.difficulty = c_genesisDifficulty; + bi.gasLimit = c_genesisGasLimit; + bi.number = 1; + bi.parentHash = sha3("parentHash"); + bytes sealedData; - SealEngineFace* se = BasicAuthority::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); - se->generateSeal(bi); { + KeyPair kp(sha3("test")); + SealEngineFace* se = BasicAuthority::createSealEngine(); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); + cdebug << se->sealers(); + bool done = false; + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.sig(); } - SealEngineFace* se = Ethash::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); - se->generateSeal(bi); - while (!done) - this_thread::sleep_for(chrono::milliseconds(50)); { + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + bool done = false; + se->setSealer("cpu"); + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.nonce(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 303512e57..612b7c685 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using byte = uint8_t; #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) namespace dev { diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index bbf4e3f2a..7006107e1 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); +AddressHash BasicAuthority::s_authorities; bool BasicAuthority::BlockHeaderRaw::verify() const { - return toAddress(recover(m_sig, hashWithout())) == Authority; + return s_authorities.count(toAddress(recover(m_sig, hashWithout()))); } bool BasicAuthority::BlockHeaderRaw::preVerify() const @@ -94,11 +94,23 @@ public: MiningProgress miningProgress() const { return MiningProgress(); } private: + virtual bool onOptionChanging(std::string const& _name, bytes const& _value) + { + RLP rlp(_value); + if (_name == "authorities") + BasicAuthority::s_authorities = rlp.toUnorderedSet
(); + else if (_name == "authority") + m_secret = rlp.toHash(); + else + return false; + return true; + } + Secret m_secret; std::function m_onSealGenerated; }; -SealEngineFace* createSealEngine() +SealEngineFace* BasicAuthority::createSealEngine() { return new BasicAuthoritySealEngine; } diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 616c18340..9127c1d53 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -30,6 +30,7 @@ #include "Sealer.h" class BasicAuthoritySeal; +class BasicAuthoritySealEngine; namespace dev { @@ -48,6 +49,8 @@ namespace eth */ class BasicAuthority { + friend class ::BasicAuthoritySealEngine; + public: // TODO: remove struct Result {}; @@ -70,6 +73,7 @@ public: Signature sig() const { return m_sig; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 1; @@ -84,7 +88,8 @@ public: }; using BlockHeader = BlockHeaderPolished; - static const Address Authority; +private: + static AddressHash s_authorities; }; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index cd55bc1f6..710279cb2 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -158,7 +158,7 @@ public: explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c3f19e723..d385163be 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -119,7 +119,7 @@ bool Ethash::BlockHeaderRaw::verify() const } #endif - auto result = EthashAux::eval(*this); + auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce); bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); @@ -281,6 +281,7 @@ public: { m_farm.onSolutionFound([=](Ethash::Solution const& sol) { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; EthashSeal s(sol.mixHash, sol.nonce); _f(&s); return true; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index eee0e3881..99baa8a05 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -94,6 +94,7 @@ public: h256 const& mixHash() const { return m_mixHash; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 2; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 42a3cf6fb..00537c21a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,18 +200,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } -Ethash::Result EthashAux::eval(BlockInfo const& _header) -{ -#if ETH_USING_ETHASH - return eval(_header, _header.proof.nonce); -#else - (void)_header; - return Ethash::Result(); -#endif -} - -#define DEV_IF_THROWS(X) try { X; } catch (...) - unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); @@ -260,17 +248,6 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) -{ -#if ETH_USING_ETHASH - return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); -#else - (void)_header; - (void)_nonce; - return Ethash::Result(); -#endif -} - Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 5ae24898d..132b9b436 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -79,8 +79,6 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header); - static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index f491240f3..28381444e 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include "Common.h" namespace dev @@ -43,6 +44,9 @@ public: class SealEngineFace { public: + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; @@ -52,6 +56,14 @@ public: // TODO: rename & generalise virtual bool isMining() const { return false; } virtual MiningProgress miningProgress() const { return MiningProgress(); } + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; }; } From 68b2c8ecbf351fde25a02fb0e2f07844ae209f0f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jul 2015 23:24:10 +0200 Subject: [PATCH 028/113] Basic test working with same code for Ethash and BasicAuthority. --- CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 1 - ethminer/MinerAux.h | 17 +-- exp/CMakeLists.txt | 6 +- exp/main.cpp | 86 +++++++------ libdevcore/Guards.h | 29 +++++ libdevcore/RLP.h | 3 + libdevcore/TrieDB.h | 9 +- libethcore/BasicAuthority.cpp | 43 ++++--- libethcore/BasicAuthority.h | 16 +-- libethcore/BlockInfo.cpp | 34 +---- libethcore/BlockInfo.h | 64 ++++++--- libethcore/Common.cpp | 3 +- libethcore/Common.h | 14 +- libethcore/Ethash.cpp | 163 ++++++++++++----------- libethcore/Ethash.h | 52 ++------ libethcore/EthashAux.cpp | 17 ++- libethcore/EthashAux.h | 47 ++++++- libethcore/Farm.h | 6 +- libethcore/Miner.h | 4 +- libethcore/ProofOfWork.cpp | 27 ---- libethcore/ProofOfWork.h | 40 ------ libethcore/Sealer.h | 31 +++-- libethereum/BlockChain.cpp | 136 ++++++++++---------- libethereum/BlockChain.h | 113 ++++++++++++++-- libethereum/BlockChainSync.cpp | 11 +- libethereum/BlockQueue.cpp | 24 ++-- libethereum/BlockQueue.h | 8 +- libethereum/CanonBlockChain.cpp | 75 ++++++----- libethereum/CanonBlockChain.h | 45 ++++++- libethereum/Client.cpp | 200 ++++++++++++++++------------- libethereum/Client.h | 119 +++++++++++------ libethereum/ClientBase.cpp | 2 +- libethereum/ClientBase.h | 4 +- libethereum/Interface.h | 8 +- libethereum/State.cpp | 87 ++++++------- libethereum/State.h | 66 ++++------ libethereum/Utility.cpp | 4 +- libethereum/Utility.h | 3 +- libweb3jsonrpc/JsonHelper.cpp | 6 +- libweb3jsonrpc/JsonHelper.h | 14 ++ test/libethcore/dagger.cpp | 3 +- test/libethereum/stateOriginal.cpp | 3 +- 44 files changed, 933 insertions(+), 716 deletions(-) delete mode 100644 libethcore/ProofOfWork.cpp delete mode 100644 libethcore/ProofOfWork.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a75b612c5..421dd1bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,8 +432,8 @@ endif () add_subdirectory(libethcore) if (GENERAL) -# add_subdirectory(libevm) -# add_subdirectory(libethereum) + add_subdirectory(libevm) + add_subdirectory(libethereum) # add_subdirectory(libwebthree) endif () diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4655240e3..2ee8928f5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -208,7 +208,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); diff --git a/eth/main.cpp b/eth/main.cpp index 1e724c7e6..8bbec9f00 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 051128669..61fde605d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #if ETH_ETHASHCL || !ETH_TRUE @@ -387,7 +386,6 @@ public: #endif } -#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -412,10 +410,10 @@ private: genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - GenericFarm f; - f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + GenericFarm f; + f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); - string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; @@ -488,20 +486,20 @@ private: jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; + GenericFarm f; if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) f.startGPU(); - ProofOfWork::WorkPackage current; + EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; while (true) try { bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) + EthashProofOfWork::Solution solution; + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { solution = sol; return completed = true; @@ -595,5 +593,4 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; -#endif }; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index fc8611ad7..b9f477385 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -25,12 +25,12 @@ if (JSONRPC) endif() #target_link_libraries(${EXECUTABLE} webthree) -#target_link_libraries(${EXECUTABLE} ethereum) -#target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) # target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash) -# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} OpenCL) endif() target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/exp/main.cpp b/exp/main.cpp index fa8603459..4a35068f1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -71,13 +70,16 @@ namespace fs = boost::filesystem; #include #include #include +#include +#include +#include +#include using namespace std; using namespace dev; using namespace eth; #endif -#if 1 - +#if 0 int main() { BlockInfo bi; @@ -124,9 +126,7 @@ int main() return 0; } - #elif 0 - int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); @@ -135,10 +135,7 @@ int main() cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); return 0; } - - #elif 0 - int main() { cdebug << "EXP"; @@ -162,9 +159,7 @@ int main() ret = orderedTrieRoot(data); cdebug << ret; } - #elif 0 - int main() { KeyManager keyman; @@ -186,7 +181,6 @@ int main() cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); } - #elif 0 int main() { @@ -246,15 +240,15 @@ int main() #elif 0 int main() { - GenericFarm f; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { BlockInfo bi = g; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { bi.proof = sol; return completed = true; @@ -289,23 +283,16 @@ int main() return 0; } -#elif 0 - -void mine(State& s, BlockChain const& _bc) +#elif 1 +void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) { s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - return completed = s.completeMine(sol); - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + _se->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); } -#elif 0 int main() { cnote << "Testing State..."; @@ -316,47 +303,62 @@ int main() Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; - cout << bc; + using Sealer = Ethash; + CanonBlockChain bc; + auto gbb = bc.headerData(bc.genesisHash()); + assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData)); + + SealEngineFace* se = Sealer::createSealEngine(); + KeyPair kp(sha3("test")); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); - cout << s; + OverlayDB stateDB = State::openDB(bc.genesisHash()); + cnote << bc; + + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); + cnote << s; // Sync up - this won't do much until we use the last state. s.sync(bc); - cout << s; + cnote << s; // Mine to get some ether! - mine(s, bc); + mine(s, bc, se); - bc.attemptImport(s.blockData(), stateDB); + bytes minedBlock = s.blockData(); + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + bc.import(minedBlock, stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; + cnote << "Miner now has" << s.balance(myMiner.address()); + s.resetCurrent(); + cnote << "Miner now has" << s.balance(myMiner.address()); // Inject a transaction to transfer funds from miner to me. Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); - cout << s; + cnote << s; // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - mine(s, bc); + mine(s, bc, se); bc.attemptImport(s.blockData(), stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; return 0; } diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 44d5969e4..135209d23 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex; using SharedMutex = boost::shared_mutex; using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; using RecursiveGuard = std::lock_guard; using ReadGuard = boost::shared_lock; using UpgradableGuard = boost::upgrade_lock; @@ -74,6 +76,33 @@ private: }; using SpinGuard = std::lock_guard; +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a94c8ba55..701f4b8e8 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -393,6 +393,9 @@ public: /// Read the byte stream. bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + /// Swap the contents of the output stream out for some other byte array. void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..05affa677 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -231,8 +231,11 @@ public: } } -protected: - DB* db() const { return m_db; } + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -383,6 +386,7 @@ public: using Super::isEmpty; using Super::root; + using Super::db; using Super::leftOvers; using Super::check; @@ -435,6 +439,7 @@ public: using Super::check; using Super::open; using Super::setRoot; + using Super::db; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7006107e1..22da67080 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -19,6 +19,7 @@ * @date 2014 */ +#include #include "Exceptions.h" #include "BasicAuthority.h" #include "BlockInfo.h" @@ -60,38 +61,38 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri } } +void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} +void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} -class BasicAuthoritySeal: public SealFace +StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const { -public: - BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + return { { "sig", toJS(m_sig) } }; +} - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - BasicAuthority::BlockHeader h(_bi); - h.m_sig = m_sig; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } -private: - Signature m_sig; -}; -class BasicAuthoritySealEngine: public SealEngineFace +class BasicAuthoritySealEngine: public SealEngineBase { public: void setSecret(Secret const& _s) { m_secret = _s; } void generateSeal(BlockInfo const& _bi) { - BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); - m_onSealGenerated(&s); + BasicAuthority::BlockHeader h(_bi); + h.m_sig = sign(m_secret, _bi.hashWithout()); + RLPStream ret; + h.streamRLP(ret); + m_onSealGenerated(ret.out()); } - void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isWorking() const { return false; } + WorkingProgress workingProgress() const { return WorkingProgress(); } private: virtual bool onOptionChanging(std::string const& _name, bytes const& _value) @@ -107,7 +108,7 @@ private: } Secret m_secret; - std::function m_onSealGenerated; + std::function m_onSealGenerated; }; SealEngineFace* BasicAuthority::createSealEngine() diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 9127c1d53..8db47938b 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -52,33 +52,31 @@ class BasicAuthority friend class ::BasicAuthoritySealEngine; public: - // TODO: remove - struct Result {}; - struct WorkPackage {}; - static const WorkPackage NullWorkPackage; - static std::string name() { return "BasicAuthority"; } static unsigned revision() { return 0; } static SealEngineFace* createSealEngine(); class BlockHeaderRaw: public BlockInfo { - friend class ::BasicAuthoritySeal; + friend class ::BasicAuthoritySealEngine; public: + static const unsigned SealFields = 1; + bool verify() const; bool preVerify() const; - WorkPackage package() const { return NullWorkPackage; } Signature sig() const { return m_sig; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 1; - void populateFromHeader(RLP const& _header, Strictness _s); + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); void streamRLPFields(RLPStream& _s) const { _s << m_sig; } void clear() { m_sig = Signature(); } void noteDirty() const {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb07162fb..64961bc40 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,10 +36,10 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt) { - RLP header = extractHeader(_block); - m_hash = sha3(header.data()); + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); populateFromHeader(header, _s); } @@ -58,7 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - m_hashWithout = h256(); + noteDirty(); } h256 const& BlockInfo::boundary() const @@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing) - { - if (gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); - - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); - - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); - - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); - } + if (_s != CheckNothing && gasUsed > gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) gasLimit = selectGasLimit(_parent); gasUsed = 0; difficulty = calculateDifficulty(_parent); + parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const @@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const void BlockInfo::verifyParent(BlockInfo const& _parent) const { - // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); - - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); - // Check timestamp is after previous timestamp. if (parentHash) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 710279cb2..b00fa73fb 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -42,10 +42,18 @@ enum Strictness { CheckEverything, QuickNonce, - IgnoreNonce, + IgnoreSeal, CheckNothing }; +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); + /** @brief Encapsulation of a block header. * Class to contain all of a block header's data. It is able to parse a block header and populate * from some given RLP block serialisation with the static fromHeader(), through the method @@ -69,7 +77,10 @@ enum Strictness */ struct BlockInfo { + friend class BlockChain; public: + static const unsigned BasicFields = 13; + // TODO: make them all private! h256 parentHash; h256 sha3Uncles; @@ -78,7 +89,7 @@ public: h256 transactionsRoot; h256 receiptsRoot; LogBloom logBloom; - u256 difficulty; + u256 difficulty; // TODO: pull out into BlockHeader u256 number; u256 gasLimit; u256 gasUsed; @@ -86,10 +97,12 @@ public: bytes extraData; BlockInfo(); - BlockInfo(bytesConstRef _block, Strictness _s); + explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); + explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -121,17 +134,14 @@ public: /// sha3 of the header only. h256 const& hashWithout() const; - h256 const& hash() const { return m_hash; } - -protected: - static RLP extractHeader(bytesConstRef _block); - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); - void streamRLPFields(RLPStream& _s) const; + h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } void clear(); void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } - static const unsigned BasicFields = 13; +protected: + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal); + void streamRLPFields(RLPStream& _s) const; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. @@ -152,35 +162,50 @@ template class BlockHeaderPolished: public BlockInfoSub { public: + static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields; + BlockHeaderPolished() {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} - explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } - explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); } + explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); } - static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } + // deprecated - just use constructor instead. + static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } + static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } - void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + // deprecated for public API - use constructor. + // TODO: make private. + void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData) + { + populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h); + } void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); BlockInfo::parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); + BlockInfoSub::populateFromParent(_parent); } + // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); + BlockInfoSub::verifyParent(_parent); } - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + // deprecated for public API - use constructor. + // TODO: make private. + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { BlockInfo::m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); + else + BlockInfo::m_hash = dev::sha3(_header.data()); if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); @@ -213,6 +238,13 @@ public: if (_i == WithProof) BlockInfoSub::streamRLPFields(_s); } + + bytes sealFieldsRLP() const + { + RLPStream s; + BlockInfoSub::streamRLPFields(s); + return s.out(); + } }; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 58e506b37..499854584 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -29,7 +29,6 @@ #include #include #include "Exceptions.h" -#include "ProofOfWork.h" #include "BlockInfo.h" using namespace std; using namespace dev; @@ -57,7 +56,7 @@ Network const c_network = Network::Frontier; Network const c_network = Network::Olympic; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 1a688fbd8..5c0a0cc79 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -124,10 +124,16 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, ///< Validate nonce + ValidSeal = 1, ///< Validate seal DontHave = 2, ///< Avoid old blocks - CheckUncles = 4, ///< Check uncle nonces - Default = ValidNonce | DontHave | CheckUncles + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures + Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + None = 0 }; }; @@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(& /** * @brief Describes the progress of a mining operation. */ -struct MiningProgress +struct WorkingProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index d385163be..128822b80 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "Exceptions.h" #include "Farm.h" #include "Miner.h" +#include "Params.h" using namespace std; using namespace std::chrono; @@ -57,8 +59,6 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); - h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) @@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); ex << errinfo_mixHash(m_mixHash); ex << errinfo_seedHash(seedHash()); - Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); ex << errinfo_difficulty(difficulty); @@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } + + if (_s != CheckNothing) + { + if (difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + + if (gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + + if (number && extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + } +} + +void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + + if (gasLimit < c_minGasLimit || + gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || + gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); +} + +void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; } bool Ethash::BlockHeaderRaw::preVerify() const @@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const return slow; } -Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const -{ - WorkPackage ret; - ret.boundary = boundary(); - ret.headerHash = hashWithout(); - ret.seedHash = seedHash(); - return ret; -} - void Ethash::BlockHeaderRaw::prep(std::function const& _f) const { EthashAux::full(seedHash(), true, _f); } +StringHashMap Ethash::BlockHeaderRaw::jsInfo() const +{ + return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; +} @@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function const& _f) const -class EthashCPUMiner: public GenericMiner, Worker +class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -190,7 +214,7 @@ private: }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker +class EthashGPUMiner: public GenericMiner, Worker { friend class dev::eth::EthashCLHook; @@ -234,66 +258,84 @@ private: }; #endif -class EthashSeal: public SealFace +struct EthashSealEngine: public SealEngineBase { -public: - EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} - - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - Ethash::BlockHeader h(_bi); - h.m_mixHash = m_mixHash; - h.m_nonce = m_nonce; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } - -private: - h256 m_mixHash; - h64 m_nonce; -}; + friend class Ethash; -struct EthashSealEngine: public SealEngineFace -{ public: EthashSealEngine() { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; #if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; #endif m_farm.setSealers(sealers); } - strings sealers() const override { return { "cpu", "opencl" }; } + strings sealers() const override + { + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; + } void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void disable() override { m_farm.stop(); } + void cancelGeneration() override { m_farm.stop(); } void generateSeal(BlockInfo const& _bi) override { - m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); m_farm.start(m_sealer); - m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + m_farm.setWork(m_sealing); // TODO: take out one before or one after... Ethash::ensurePrecomputed((unsigned)_bi.number); } - void onSealGenerated(std::function const& _f) override + void onSealGenerated(std::function const& _f) override { - m_farm.onSolutionFound([=](Ethash::Solution const& sol) + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) { cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - EthashSeal s(sol.mixHash, sol.nonce); - _f(&s); + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); return true; }); } private: bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; }; +void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + // Go via the farm since the handler function object is stored as a local within the Farm's lambda. + // Has the side effect of stopping local workers, which is good, as long as it only does it for + // valid submissions. + static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); +} + +bool Ethash::isWorking(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.isMining(); + return false; +} + +WorkingProgress Ethash::workingProgress(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.miningProgress(); + return WorkingProgress(); +} + SealEngineFace* Ethash::createSealEngine() { return new EthashSealEngine; @@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE -using UniqueGuard = std::unique_lock; - -template -class Notified -{ -public: - Notified() {} - Notified(N const& _v): m_value(_v) {} - Notified(Notified const&) = delete; - Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - - operator N() const { UniqueGuard l(m_mutex); return m_value; } - - void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } - -private: - mutable Mutex m_mutex; - mutable std::condition_variable m_cv; - N m_value; -}; - class EthashCLHook: public ethash_cl_miner::search_hook { public: diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99baa8a05..576621bd4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -53,59 +53,42 @@ public: static unsigned revision(); static SealEngineFace* createSealEngine(); - // TODO: remove or virtualize - struct Solution - { - h64 nonce; - h256 mixHash; - }; - // TODO: make private - struct Result - { - h256 value; - h256 mixHash; - }; - // TODO: virtualise - struct WorkPackage - { - WorkPackage() = default; - - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } + using Nonce = h64; - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; - }; - static const WorkPackage NullWorkPackage; + static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce); + static bool isWorking(SealEngineFace* _engine); + static WorkingProgress workingProgress(SealEngineFace* _engine); class BlockHeaderRaw: public BlockInfo { - friend class EthashSeal; + friend class EthashSealEngine; public: + static const unsigned SealFields = 2; + bool verify() const; bool preVerify() const; void prep(std::function const& _f = std::function()) const; - WorkPackage package() const; h256 const& seedHash() const; - h64 const& nonce() const { return m_nonce; } + Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 2; - void populateFromHeader(RLP const& _header, Strictness _s); - void clear() { m_mixHash = h256(); m_nonce = h64(); } + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); + void clear() { m_mixHash = h256(); m_nonce = Nonce(); } void noteDirty() const { m_seedHash = h256(); } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - h64 m_nonce; + Nonce m_nonce; h256 m_mixHash; mutable h256 m_seedHash; @@ -115,13 +98,6 @@ public: // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); - - /// Default value of the local work size. Also known as workgroup size. - static const unsigned defaultLocalWorkSize; - /// Default value of the global work size as a multiplier of the local work size - static const unsigned defaultGlobalWorkSizeMultiplier; - /// Default value of the milliseconds per global work size (per batch) - static const unsigned defaultMSPerBatch; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 00537c21a..c511978db 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; } EthashAux* dev::eth::EthashAux::s_this = nullptr; +const unsigned EthashProofOfWork::defaultLocalWorkSize = 64; +const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE +const unsigned EthashProofOfWork::defaultMSPerBatch = 0; +const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage(); + EthashAux::~EthashAux() { } @@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; } -Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) if (FullType dag = get()->m_fulls[_seedHash].lock()) return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { - return Ethash::Result{ ~h256(), h256() }; + return EthashProofOfWork::Result{ ~h256(), h256() }; } } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 132b9b436..d42e46d91 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -34,6 +34,47 @@ namespace eth struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; +/// Proof of work definition for Ethash. +struct EthashProofOfWork +{ + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + WorkPackage() = default; + WorkPackage(Ethash::BlockHeader const& _bh): + boundary(_bh.boundary()), + headerHash(_bh.hashWithout()), + seedHash(_bh.seedHash()) + {} + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; +}; + class EthashAux { public: @@ -46,7 +87,7 @@ public: LightAllocation(h256 const& _seedHash); ~LightAllocation(); bytesConstRef data() const; - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; ethash_light_t light; uint64_t size; }; @@ -55,7 +96,7 @@ public: { FullAllocation(ethash_light_t _light, ethash_callback_t _cb); ~FullAllocation(); - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; bytesConstRef data() const; uint64_t size() const { return ethash_full_dag_size(full); } ethash_full_t full; @@ -79,7 +120,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: EthashAux() {} diff --git a/libethcore/Farm.h b/libethcore/Farm.h index b69f8325a..c86b4804e 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -123,9 +123,9 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const + WorkingProgress const& miningProgress() const { - MiningProgress p; + WorkingProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); @@ -195,7 +195,7 @@ private: std::atomic m_isMining = {false}; mutable SharedMutex x_progress; - mutable MiningProgress m_progress; + mutable WorkingProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 03eba9880..90a5902c4 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,9 +36,9 @@ namespace dev namespace eth { -struct MineInfo: public MiningProgress {}; +struct MineInfo: public WorkingProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) +inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p) { _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp deleted file mode 100644 index 843db72c7..000000000 --- a/libethcore/ProofOfWork.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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 ProofOfWork.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "ProofOfWork.h" -#include "BlockInfo.h" -using namespace std; -using namespace dev; -using namespace eth; - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h deleted file mode 100644 index f55c54df6..000000000 --- a/libethcore/ProofOfWork.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 ProofOfWork.h - * @author Gav Wood - * @date 2014 - * - * Determines the PoW algorithm. - */ - -#pragma once - -#include -#include -#include "Common.h" -//#include "Ethash.h" -#include "BasicAuthority.h" - -namespace dev -{ -namespace eth -{ - -using ProofOfWork = BasicAuthority; - -} -} diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index 28381444e..137659dfc 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -25,6 +25,7 @@ #include #include +#include #include "Common.h" namespace dev @@ -34,28 +35,22 @@ namespace eth class BlockInfo; -class SealFace -{ -public: - virtual bool wouldSealHeader(BlockInfo const&) const { return true; } - virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; -}; - class SealEngineFace { public: + virtual std::string name() const = 0; + virtual unsigned revision() const = 0; + virtual unsigned sealFields() const = 0; + virtual bytes sealRLP() const = 0; + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; - virtual void onSealGenerated(std::function const& _f) = 0; - virtual void disable() {} - - // TODO: rename & generalise - virtual bool isMining() const { return false; } - virtual MiningProgress miningProgress() const { return MiningProgress(); } + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} protected: virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } @@ -66,5 +61,15 @@ private: std::unordered_map m_options; }; +template +class SealEngineBase: public SealEngineFace +{ +public: + std::string name() const override { return Sealer::name(); } + unsigned revision() const override { return Sealer::revision(); } + unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; } + bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); } +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 14b13b90d..aae8cbd10 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,12 +35,12 @@ #include #include #include -#include #include #include #include #include "GenesisInfo.h" #include "State.h" +#include "Utility.h" #include "Defaults.h" using namespace std; @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 1 +#define ETH_CATCH 0 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 @@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): + m_genesisState(_genesisState) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit // Initialise with the genesis as the last block on the longest chain. m_genesisBlock = _genesisBlock; m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); + m_genesisState = _genesisState; + + // remove the next line real soon. we don't need to be supporting this forever. + upgradeDatabase(_path, genesisHash()); if (open(_path, _we) != c_minorProtocolVersion) rebuild(_path, _p); @@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); - BlockInfo bi(b); + BlockInfo bi(&b); if (_prepPoW) - Ethash::prep(bi); + Ethash::ensurePrecomputed((unsigned)bi.number); if (bi.parentHash != lastHash) { @@ -351,7 +356,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; @@ -388,7 +393,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad, _ir); + block = verifyBlock(&_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) @@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& auto parentBlock = block(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; - clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); + clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); @@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(_block, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this); for (unsigned i = 0; i < s.pending().size(); ++i) { @@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db) try { cout << "block..." << flush; - BlockInfo bi = info(h); - cout << "details..." << flush; - BlockDetails bd = details(h); + BlockInfo bi(block(h)); + cout << "extras..." << flush; + details(h); cout << "state..." << flush; if (_db.exists(bi.stateRoot)) break; @@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +bytes BlockChain::headerData(h256 const& _hash) const { - VerifiedBlockRef res; - try - { - Strictness strictness = Strictness::CheckEverything; - if (~_ir & ImportRequirements::ValidNonce) - strictness = Strictness::IgnoreNonce; + if (_hash == m_genesisHash) + return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes(); - res.info.populate(_block, strictness); - res.info.verifyInternals(&_block); - } - catch (Exception& ex) { - ex << errinfo_phase(1); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; + ReadGuard l(x_blocks); + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + return BlockInfo::extractHeader(&it->second).data().toBytes(); } - RLP r(_block); - unsigned i = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_uncleIndex(i); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; - } - i = 0; - for (RLP const& tr: r[1]) + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + + if (d.empty()) { - bytesConstRef d = tr.data(); - try - { - res.transactions.push_back(Transaction(d, CheckTransaction::Everything)); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_transactionIndex(i); - ex << errinfo_transaction(d.toBytes()); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; + cwarn << "Couldn't find requested block:" << _hash; + return bytes(); } - res.block = bytesConstRef(&_block); - return res; + + noteUsed(_hash); + + WriteGuard l(x_blocks); + m_blocks[_hash].resize(d.size()); + memcpy(m_blocks[_hash].data(), d.data(), d.size()); + + return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes(); } +State BlockChain::genesisState(OverlayDB const& _db) +{ + State ret(_db, BaseState::Empty); + dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? + ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. + ret.m_previousBlock = BlockInfo(&m_genesisBlock); + return ret; +} + + + + + + + + + + + + + + + + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 638c9c3af..50965f2b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,6 +37,7 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" +#include "State.h" namespace std { @@ -86,6 +87,13 @@ enum { }; using ProgressCallback = std::function; +using StateDefinition = std::unordered_map; + +class VersionChecker +{ +public: + VersionChecker(std::string const& _dbPath, h256 const& _genesisHash); +}; /** * @brief Implements the blockchain database. All data this gives is disk-backed. @@ -94,7 +102,7 @@ using ProgressCallback = std::function; class BlockChain { public: - BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); ~BlockChain(); /// Attempt a database re-open. @@ -120,14 +128,17 @@ public: /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; - /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. - BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); } + /// Get the partial-header of a block (or the most recent mined if none given). Thread-safe. + BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); } BlockInfo info() const { return info(currentHash()); } /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. bytes block(h256 const& _hash) const; bytes block() const { return block(currentHash()); } - bytes oldBlock(h256 const& _hash) const; + + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes headerData(h256 const& _hash) const; + bytes headerData() const { return headerData(currentHash()); } /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. BlockDetails details(h256 const& _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } @@ -264,13 +275,16 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); - /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); - /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } -private: + /// Get a pre-made genesis State object. + State genesisState(OverlayDB const& _db); + + /// Verify block and prepare it for enactment + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + +protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); @@ -345,6 +359,7 @@ private: /// Genesis block info. h256 m_genesisHash; bytes m_genesisBlock; + std::unordered_map m_genesisState; ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; @@ -354,6 +369,88 @@ private: friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; +template +class FullBlockChain: public BlockChain +{ +public: + using BlockHeader = typename Sealer::BlockHeader; + + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path, _we, _p) + {} + + /// Get the header of a block (or the most recent mined if none given). Thread-safe. + typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } + typename Sealer::BlockHeader header() const { return header(currentHash()); } + + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + { + VerifiedBlockRef res; + + try + { + BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); + h.verifyInternals(_block); + h.verifyParent(header(h.parentHash)); + res.info = static_cast(h); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + if (_ir && ImportRequirements::UncleBasic) + for (auto const& uncle: r[2]) + { + try + { + BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + if (_ir && ImportRequirements::TransactionBasic) + for (RLP const& tr: r[1]) + { + bytesConstRef d = tr.data(); + try + { + res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None)); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_transactionIndex(i); + ex << errinfo_transaction(d.toBytes()); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + res.block = bytesConstRef(_block); + return res; + } +}; + std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); } diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 6aede0c16..ed022fb75 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const for (unsigned i = 0; i < itemCount; ++i) { - auto h = BlockInfo::headerHash(_r[i].data()); + auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) + switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; @@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const logNewBlock(h); if (m_state == SyncState::NewBlocks) { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); + BlockInfo bi(_r[i].data()); if (bi.number > maxUnknownNumber) { maxUnknownNumber = bi.number; @@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP con { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); + auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { - switch (host().bq().import(_r[0].data(), host().chain())) + switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b6c548c1f..6b400b236 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); } catch (...) { @@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() } } -ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) +ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. - h256 h = BlockInfo::headerHash(_block); + h256 h = BlockInfo::headerHashFromBlock(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; @@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::AlreadyKnown; } - // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { - // TODO: quick verify - bi.populate(_block); - bi.verifyInternals(_block); + // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer + // VERIFY: populates from the block and checks the block is internally coherent. + bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info; } catch (Exception const& _e) { @@ -218,7 +216,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! - if (_bc.isKnown(h)) + if (m_bc->isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; @@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else @@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; @@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad) return !m_readySet.empty(); } -void BlockQueue::tick(BlockChain const& _bc) +void BlockQueue::tick() { vector> todo; { @@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc) cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) - import(&b.second, _bc); + import(&b.second); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index b9e6f5b3b..97fca7c72 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -76,11 +76,13 @@ public: BlockQueue(); ~BlockQueue(); + void setChain(BlockChain const& _bc) { m_bc = &_bc; } + /// Import a block into the queue. - ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. - void tick(BlockChain const& _bc); + void tick(); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. @@ -138,6 +140,8 @@ private: void updateBad_WITH_LOCK(h256 const& _bad); void drainVerified_WITH_BOTH_LOCKS(); + BlockChain const* m_bc; ///< The blockchain into which our imports go. + mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. h256Hash m_readySet; ///< All blocks ready for chain import. diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 4e6d89243..eee4b98b7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -41,14 +40,44 @@ namespace js = json_spirit; #define ETH_CATCH 1 -std::unordered_map const& dev::eth::genesisState() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); +std::string CanonBlockChain::s_genesisStateJSON; + +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) +{ +} + +bytes CanonBlockChain::createGenesisBlock() +{ + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + SecureTrieDB state(&db); + state.init(); + dev::eth::commit(createGenesisState(), state); + stateRoot = state.root(); + } + + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +unordered_map CanonBlockChain::createGenesisState() { static std::unordered_map s_ret; if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(c_genesisInfo, val); + json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()) { u256 balance; @@ -68,53 +97,29 @@ std::unordered_map const& dev::eth::genesisState() return s_ret; } -// TODO: place Registry in here. - -std::unique_ptr CanonBlockChain::s_genesis; -boost::shared_mutex CanonBlockChain::x_genesis; -Nonce CanonBlockChain::s_nonce(u64(42)); - -bytes CanonBlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - SecureTrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - BlockChain(createGenesisBlock(), _path, _we, _pc) +void CanonBlockChain::setGenesisState(std::string const& _json) { + WriteGuard l(x_genesis); + s_genesisStateJSON = _json; + s_genesis.reset(); } -void CanonBlockChain::setGenesisNonce(Nonce const& _n) +void CanonBlockChain::setGenesisNonce(Nonce const& _n) { WriteGuard l(x_genesis); s_nonce = _n; s_genesis.reset(); } -BlockInfo const& CanonBlockChain::genesis() +Ethash::BlockHeader const& CanonBlockChain::genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); - s_genesis.reset(new BlockInfo); - s_genesis->populate(&gb); + s_genesis.reset(new Ethash::BlockHeader); + s_genesis->populate(&gb, CheckEverything); } return *s_genesis; } diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index c16479f0d..d79926703 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BlockDetails.h" #include "Account.h" @@ -45,7 +46,32 @@ std::unordered_map const& genesisState(); * @threadsafe * @todo Make not memory hog (should actually act as a cache and deallocate old entries). */ -class CanonBlockChain: public BlockChain +template +class CanonBlockChain: public FullBlockChain +{ +public: + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + ~CanonBlockChain() {} + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock() + { + RLPStream block(3); + block.appendList(Sealer::BlockHeader::Fields) + << h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string(); + bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP(); + block.appendRaw(sealFields, Sealer::BlockHeader::SealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); + } +}; + +template <> +class CanonBlockChain: public FullBlockChain { public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} @@ -53,22 +79,35 @@ public: ~CanonBlockChain() {} /// @returns the genesis block header. - static BlockInfo const& genesis(); + static Ethash::BlockHeader const& genesis(); /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static std::unordered_map createGenesisState(); + /// Alter the value of the genesis block's nonce. /// @warning Unless you're very careful, make sure you call this right at the start of the /// program, before anything has had the chance to use this class at all. static void setGenesisNonce(Nonce const& _n); + /// Alter all the genesis block's state by giving a JSON string with account details. + /// @TODO implement. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisState(std::string const&); + + // TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, + private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + static std::unique_ptr s_genesis; static Nonce s_nonce; + static std::string s_genesisStateJSON; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 918480263..ec37302a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -72,47 +72,43 @@ static const Addresses c_canaries = Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph }; -VersionChecker::VersionChecker(string const& _dbPath) +Client::Client(std::shared_ptr _gp): + Worker("eth", 0), + m_gp(_gp ? _gp : make_shared()) { - upgradeDatabase(_dbPath); } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Client(_extNet, make_shared(), _dbPath, _forceAction, _networkId) +void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId) { - startWorking(); -} + // Cannot be opened until after blockchain is open, since BlockChain may upgrade the database. + // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database + // until after the construction. + m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); + m_preMine = State(m_stateDB); + m_postMine = State(m_stateDB); + // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. + m_preMine = bc().genesisState(m_stateDB); -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth", 0), - m_vc(_dbPath), - m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), - m_gp(_gp), - m_stateDB(State::openDB(_dbPath, _forceAction)), - m_preMine(m_stateDB, BaseState::CanonGenesis), - m_postMine(m_stateDB) -{ - if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + m_bq.setChain(bc()); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_sealEngine = shared_ptr(Ethash::createSealEngine()); - m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); + bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_gp->update(m_bc); + if (_forceAction == WithExisting::Rescue) + m_bc.rescue(m_stateDB); + + m_gp->update(bc()); - auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); + auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId)); m_host = host; _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common if (_dbPath.size()) Defaults::setDBPath(_dbPath); doWork(); - startWorking(); } @@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000) this_thread::sleep_for(std::chrono::milliseconds(500)); - return m_bq.import(&_block, bc(), _isSafe); + return m_bq.import(&_block, _isSafe); } tuple Client::syncQueue(unsigned _max) { stopWorking(); - return m_bc.sync(m_bq, m_stateDB, _max); + return bc().sync(m_bq, m_stateDB, _max); } void Client::onBadBlock(Exception& _ex) const @@ -294,7 +290,7 @@ void Client::startedWorking() clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -309,7 +305,7 @@ void Client::doneWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -328,7 +324,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.disable(); + m_sealEngine->cancelGeneration(); { WriteGuard l(x_postMine); @@ -340,10 +336,10 @@ void Client::killChain() m_working = State(); m_stateDB = OverlayDB(); - m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); - m_bc.reopen(Defaults::dbPath(), WithExisting::Kill); + m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); + bc().reopen(Defaults::dbPath(), WithExisting::Kill); - m_preMine = State(m_stateDB, BaseState::CanonGenesis); + m_preMine = bc().genesisState(m_stateDB); m_postMine = State(m_stateDB); } @@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); - auto receipts = m_bc.receipts(_block).receipts; + auto d = bc().info(_block); + auto receipts = bc().receipts(_block).receipts; Guard l(x_filtersWatches); io_changed.insert(ChainChangedFilter); @@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable) startMining(); } -MiningProgress Client::miningProgress() const +bool Client::isMining() const { - if (m_farm.isMining()) - return m_farm.miningProgress(); - return MiningProgress(); + return Ethash::isWorking(m_sealEngine.get()); +} + +WorkingProgress Client::miningProgress() const +{ + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()); + return WorkingProgress(); } uint64_t Client::hashrate() const { - if (m_farm.isMining()) - return m_farm.miningProgress().rate(); + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()).rate(); return 0; } @@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -ProofOfWork::WorkPackage Client::getWork() -{ - // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. - // this will be reset as soon as a new block arrives, allowing more transactions to be processed. - bool oldShould = shouldServeWork(); - m_lastGetWork = chrono::system_clock::now(); - - if (!m_mineOnBadChain && isChainBad()) - return ProofOfWork::WorkPackage(); - - // if this request has made us bother to serve work, prep it now. - if (!oldShould && shouldServeWork()) - onPostStateChanged(); - else - // otherwise, set this to true so that it gets prepped next time. - m_remoteWorking = true; - return ProofOfWork::package(m_miningInfo); -} - -bool Client::submitWork(ProofOfWork::Solution const& _solution) -{ - bytes newBlock; - DEV_WRITE_GUARDED(x_working) - if (!m_working.completeMine(_solution)) - return false; - - DEV_READ_GUARDED(x_working) - { - DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; - newBlock = m_working.blockData(); - } - - // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. - m_bq.import(&newBlock, m_bc, true); - - return true; -} - unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; @@ -553,7 +515,7 @@ void Client::syncBlockQueue() ImportRoute ir; unsigned count; Timer t; - tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); if (count) @@ -577,7 +539,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; DEV_WRITE_GUARDED(x_working) - tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp); if (newPendingReceipts.empty()) return; @@ -590,7 +552,7 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restart mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& h: _ir.deadBlocks) { clog(ClientTrace) << "Dead block:" << h; - for (auto const& t: m_bc.transactions(h)) + for (auto const& t: bc().transactions(h)) { clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, IfDropped::Retry); @@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir) newPreMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + preChanged = newPreMine.sync(bc()); if (preChanged || m_postMine.address() != m_preMine.address()) { @@ -700,7 +662,7 @@ void Client::rejigMining() { clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) - m_working.commitToMine(m_bc, m_extraData); + m_working.commitToMine(bc(), m_extraData); DEV_READ_GUARDED(x_working) { DEV_WRITE_GUARDED(x_postMine) @@ -709,10 +671,10 @@ void Client::rejigMining() } if (m_wouldMine) - m_farm.sealBlock(m_miningInfo); + m_sealEngine->generateSeal(m_miningInfo); } if (!m_wouldMine) - m_farm.disable(); + m_sealEngine->cancelGeneration(); } void Client::noteChanged(h256Hash const& _filters) @@ -768,7 +730,7 @@ void Client::tick() { m_report.ticks++; checkWatchGarbage(); - m_bq.tick(m_bc); + m_bq.tick(); m_lastTick = chrono::system_clock::now(); if (m_report.ticks == 15) clog(ClientTrace) << activityReport(); @@ -792,7 +754,7 @@ void Client::checkWatchGarbage() uninstallWatch(i); // blockchain GC - m_bc.garbageCollect(); + bc().garbageCollect(); m_lastGarbageCollection = chrono::system_clock::now(); } @@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const try { State ret(m_stateDB); - ret.populateFromChain(m_bc, _block); + ret.populateFromChain(bc(), _block); return ret.fromPending(_txi); } catch (Exception& ex) @@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const try { State ret(m_stateDB); - PopulationStatistics s = ret.populateFromChain(m_bc, _block); + PopulationStatistics s = ret.populateFromChain(bc(), _block); if (o_stats) swap(s, *o_stats); return ret; @@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const auto h = m_host.lock(); return h ? h->status() : SyncStatus(); } + +bool Client::submitSealed(bytes const& _header) +{ + DEV_WRITE_GUARDED(x_working) + if (!m_working.sealBlock(_header)) + return false; + + bytes newBlock; + DEV_READ_GUARDED(x_working) + { + DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + newBlock = m_working.blockData(); + } + + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. + return m_bq.import(&newBlock, true) == ImportResult::Success; +} + + + + + + + + + + + + + + +std::tuple EthashClient::getEthashWork() +{ + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); + m_lastGetWork = chrono::system_clock::now(); + + if (!m_mineOnBadChain && isChainBad()) + return std::tuple(); + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; + Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + return std::tuple(bh.boundary(), bh.hashWithout(), bh.seedHash()); +} + +bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce) +{ + Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce); + return true; +} + diff --git a/libethereum/Client.h b/libethereum/Client.h index 9ae7c7e09..73609bd71 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -60,12 +60,6 @@ enum ClientWorkState Deleted }; -class VersionChecker -{ -public: - VersionChecker(std::string const& _dbPath); -}; - struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; @@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); /** * @brief Main API hub for interfacing with Ethereum. + * Not to be used directly - subclass. */ class Client: public ClientBase, Worker { public: /// New-style Constructor. - explicit Client( - p2p::Host* _host, - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); - - explicit Client( - p2p::Host* _host, - std::shared_ptr _gpForAdoption, // pass it in with new. - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); + /// Any final derived class's constructor should make sure they call init(). + explicit Client(std::shared_ptr _gpForAdoption); /// Destructor. virtual ~Client(); @@ -129,7 +112,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. - CanonBlockChain const& blockChain() const { return m_bc; } + BlockChain const& blockChain() const { return bc(); } /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. @@ -176,26 +159,16 @@ public: /// NOT thread-safe void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? - bool isMining() const override { return m_farm.isMining(); } + bool isMining() const override; /// Are we mining now? bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MiningProgress miningProgress() const override; + WorkingProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); - /// Update to the latest transactions and get hash of the current block to be mined minus the - /// nonce (the 'work hash') and the difficulty to be met. - virtual ProofOfWork::WorkPackage getWork() override; - - /** @brief Submit the proof for the proof-of-work. - * @param _s A valid solution. - * @return true if the solution was indeed valid and accepted. - */ - virtual bool submitWork(ProofOfWork::Solution const& _proof) override; - // Debug stuff: DownloadMan const* downloadMan() const; @@ -218,12 +191,20 @@ public: /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } /// Rewind to a prior head. - void rewind(unsigned _n) { m_bc.rewind(_n); } + void rewind(unsigned _n) { bc().rewind(_n); } + /// Rescue the chain. + void rescue() { bc().rescue(m_stateDB); } + /// Get the seal engine. + SealEngineFace* sealEngine() const { return m_sealEngine.get(); } protected: + /// Perform critical setup functions. + /// Must be called in the constructor of the finally derived class. + void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); + /// InterfaceStub methods - virtual BlockChain& bc() override { return m_bc; } - virtual BlockChain const& bc() const override { return m_bc; } + virtual BlockChain& bc() override = 0; + virtual BlockChain const& bc() const override = 0; /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. @@ -245,7 +226,10 @@ protected: /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. void noteChanged(h256Hash const& _filters); -private: + /// Submit + bool submitSealed(bytes const& _s); + +protected: /// Called when Worker is starting. void startedWorking() override; @@ -291,8 +275,6 @@ private: /// @warning May be called from any thread. void onBadBlock(Exception& _ex) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -339,5 +321,64 @@ private: bytes m_extraData; }; +template +class SpecialisedClient: public Client +{ +public: + explicit SpecialisedClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): + Client(_gpForAdoption), + m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }) + { + m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSealGenerated([=](bytes const& header){ + return this->submitSealed(header); + }); + init(_host, _dbPath, _forceAction, _networkId); + } + + /// Get the object representing the current canonical blockchain. + CanonBlockChain const& blockChain() const { return m_bc; } + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } + +protected: + CanonBlockChain m_bc; ///< Maintains block database. +}; + +class EthashClient: public SpecialisedClient +{ +public: + /// Trivial forwarding constructor. + explicit EthashClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + + /// Update to the latest transactions and get hash of the current block to be mined minus the + /// nonce (the 'work hash') and the difficulty to be met. + virtual std::tuple getEthashWork() override; + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ + virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } +}; + } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f463b0195..769880269 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const auto bl = bc().block(_blockHash); RLP b(bl); if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); + return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData); else return BlockInfo(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 82f03def0..874f10548 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -156,9 +156,7 @@ public: virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } - virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } - virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } - virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } + virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 973433af9..213e7fb26 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" @@ -207,12 +207,12 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual ProofOfWork::WorkPackage getWork() = 0; + virtual std::tuple getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); } /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; + virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); } /// Check the progress of the mining. - virtual MiningProgress miningProgress() const = 0; + virtual WorkingProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1656109a9..ee2078a07 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } -OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) +OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; @@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) boost::filesystem::remove_all(path + "/state"); } - path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); + path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); ldb::Options o; @@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("beginning of Genesis construction.", true); - if (_bs == BaseState::CanonGenesis) - { - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); - - paranoia("after DB commit of Genesis construction.", true); - m_previousBlock = CanonBlockChain::genesis(); - } - else - m_previousBlock.clear(); - - resetCurrent(); - - assert(m_state.root() == m_previousBlock.stateRoot); + m_previousBlock.clear(); + m_currentBlock.clear(); +// assert(m_state.root() == m_previousBlock.stateRoot); paranoia("end of normal construction.", true); } @@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip; - bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip, _ir); + BlockInfo bip(_bc.block(bi.parentHash)); + sync(_bc, bi.parentHash, bip); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; - auto vb = BlockChain::verifyBlock(b); + auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); t.restart(); - enact(vb, _bc, _ir); + enact(vb, _bc); ret.enact = t.elapsed(); } else @@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi, _ir); + sync(_bc, _h, bi); } return ret; @@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ void State::commit() { - m_touched += dev::eth::commit(m_cache, m_db, m_state); + m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } @@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) +bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi) { - (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -355,7 +342,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor { cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; - cwarn << "Bailing."; + cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); } m_previousBlock = bi; @@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) { #if ETH_TIMED_ENACTMENTS Timer t; @@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _ir); + auto ret = enact(_block, _bc); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire RLP rlp(_block); cleanup(false); - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal); m_currentBlock = bi; m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); @@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) { DEV_TIMED_FUNCTION_ABOVE(500); @@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = _block.info; m_currentBlock.noteDirty(); + m_currentBlock = _block.info; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } @@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + // IgnoreSeal since it's a VerifiedBlock. + BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; if (!_bc.isKnown(uncle.parentHash)) @@ -829,6 +817,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { + (void)_bc; + /* commitToMine(_bc); // Update difficulty according to timestamp. @@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out(), std::function(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) { cwarn << "Bad block: " << _e.what(); } - +*/ return false; } @@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) for (auto const& u: us) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { - BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithProof); + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); ++unclesCount; - uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) break; } @@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) m_committedToMine = true; } -void State::completeMine() +bool State::sealBlock(bytesConstRef _header) { - cdebug << "Completing mine!"; + if (!m_committedToMine) + return false; + + cdebug << "Sealing block!"; // Got it! // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithProof); + ret.appendRaw(_header); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); - m_currentBlock.noteDirty(); + m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; -/* StructuredLogger::minedNewBlock( + // TODO: move into Sealer + StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.proof.nonce.abridged(), + "", // Can't give the nonce here. "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - );*/ + ); // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. @@ -989,6 +982,8 @@ void State::completeMine() m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; + + return true; } bool State::addressInUse(Address _id) const diff --git a/libethereum/State.h b/libethereum/State.h index f6a8471ea..805215ee5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "Account.h" @@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati enum class BaseState { PreExisting, - Empty, - CanonGenesis + Empty }; enum class Permanence @@ -104,6 +102,7 @@ class State friend class dev::test::ImportTest; friend class dev::test::StateLoader; friend class Executive; + friend class BlockChain; public: /// Default constructor; creates with a blank database prepopulated with the genesis block. @@ -125,7 +124,7 @@ public: ~State(); /// Construct state object from arbitrary point in blockchain. - PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None); /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. @@ -133,8 +132,8 @@ public: Address address() const { return m_ourAddress; } /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. - static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust); - static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } + static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); } OverlayDB const& db() const { return m_db; } OverlayDB& db() { return m_db; } @@ -163,22 +162,20 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. - template - bool completeMine(typename PoW::Solution const& _result) - { - if (!m_committedToMine) - return false; - - m_currentBlock.proof = _result; - if (!PoW::verify(m_currentBlock)) - return false; - -// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - - completeMine(); - - return true; - } + /// TODO: verify it prior to calling this. + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * while (notYetMined) + * { + * // lock + * commitToMine(_blockChain); // will call uncommitToMine if a repeat. + * completeMine(); + * // unlock + * @endcode + */ + bool sealBlock(bytes const& _header) { return sealBlock(&_header); } + bool sealBlock(bytesConstRef _header); /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. @@ -295,11 +292,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); + bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -313,19 +310,6 @@ public: void resetCurrent(); private: - /** Commit to DB and build the final block if the previous call to mine()'s result is completion. - * Typically looks like: - * @code - * while (notYetMined) - * { - * // lock - * commitToMine(_blockChain); // will call uncommitToMine if a repeat. - * completeMine(); - * // unlock - * @endcode - */ - void completeMine(); - /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -340,7 +324,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -386,7 +370,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, SecureTrieDB& _state) { AddressHash ret; for (auto const& i: _cache) @@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, } else { - SecureTrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); @@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, if (i.second.isFreshCode()) { h256 ch = sha3(i.second.code()); - _db.insert(ch, &i.second.code()); + _state.db()->insert(ch, &i.second.code()); s << ch; } else diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index e02012cd5..1b97f82e7 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args) return m_data; } -void dev::eth::upgradeDatabase(std::string const& _basePath) +void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash) { std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath; @@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath) { auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; - auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash; string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(databaseVersion); diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 0dfe8509b..df48269ec 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -42,7 +43,7 @@ namespace eth */ bytes parseData(std::string const& _args); -void upgradeDatabase(std::string const& _basePath); +void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash); } } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 7d63ed165..15d39bded 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); -#if ETH_USING_ETHASH // TODO: move into ProofOfWork. - res["nonce"] = toJS(_bi.proof.nonce); - res["seedHash"] = toJS(_bi.proofCache()); -#endif +// res["nonce"] = toJS(_bi.proof.nonce); +// res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..624a73e54 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. +template +Json::Value toJson(BlockHeaderPolished const& _bh) +{ + Json::Value res; + if (_bh) + { + res = toJson(static_cast(_bh)); + for (auto const& i: _bh.jsInfo()) + res[i.first] = i.second; + } + return res; +} + } namespace shh diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 1743882e5..061b5ae79 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -24,7 +24,6 @@ #include #include "../JsonSpiritHeaders.h" #include -#include #include #include #include "../TestHelper.h" @@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - Ethash::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 452163061..e3f8ac29f 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. From 487349bf099873b28578055358f1c86619ef0711 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:29:03 +0200 Subject: [PATCH 029/113] All fields of BlockInfo now private. --- alethzero/MainWin.cpp | 34 +++--- ethminer/MinerAux.h | 4 +- evmjit/libevmjit-cpp/JitVM.cpp | 6 +- evmjit/libevmjit/RuntimeManager.cpp | 6 +- exp/main.cpp | 6 +- libethcore/BasicAuthority.cpp | 8 +- libethcore/BlockInfo.cpp | 104 ++++++++--------- libethcore/BlockInfo.h | 91 +++++++++------ libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 40 +++---- libethcore/EthashAux.cpp | 2 +- libethereum/BasicGasPricer.cpp | 6 +- libethereum/BlockChain.cpp | 78 +++++-------- libethereum/BlockChain.h | 2 +- libethereum/BlockChainSync.cpp | 6 +- libethereum/BlockQueue.cpp | 50 ++++---- libethereum/Executive.cpp | 10 +- libethereum/State.cpp | 133 +++++++++++----------- libethereum/State.h | 2 +- libevm/ExtVMFace.h | 4 +- libevm/VM.cpp | 10 +- libtestutils/BlockChainLoader.cpp | 2 +- libweb3jsonrpc/JsonHelper.cpp | 22 ++-- test/TestHelper.cpp | 6 +- test/libethereum/ClientBase.cpp | 18 +-- test/libethereum/blockchain.cpp | 78 ++++++------- test/libethereum/genesis.cpp | 2 +- test/libevm/vm.cpp | 12 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- third/MainWin.cpp | 2 +- 30 files changed, 378 insertions(+), 370 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2ee8928f5..ad8f5528c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,7 +189,7 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; @@ -1629,7 +1629,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1706,7 +1706,7 @@ void Main::on_blocks_currentItemChanged() if (item->data(Qt::UserRole + 1).isNull()) { char timestamp[64]; - time_t rawTime = (time_t)(uint64_t)info.timestamp; + time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; s << "

#" << info.number; @@ -1714,7 +1714,7 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; - s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "" << "
"; + s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; @@ -1724,7 +1724,7 @@ void Main::on_blocks_currentItemChanged() { auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; - s << "
Parent: " << info.parentHash << "" << "
"; + s << "
Parent: " << info.parentHash() << "" << "
"; } else { @@ -1732,20 +1732,20 @@ void Main::on_blocks_currentItemChanged() s << "
Parent: It was a virgin birth
"; } // s << "
Bloom: " << details.bloom << ""; - if (!!info.logBloom) - s << "
Log Bloom: " << info.logBloom << "
"; + if (!!info.logBloom()) + s << "
Log Bloom: " << info.logBloom() << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; - s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Parent: " << uncle.parentHash() << "" << ""; s << line << "Number: " << uncle.number << "" << ""; - s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; @@ -1754,20 +1754,20 @@ void Main::on_blocks_currentItemChanged() auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } - if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; + if (info.parentHash()) + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; else s << "
Pre: Nothing is before Phil" << "
"; - s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; + s << "
Receipts: @" << info.receiptsRoot() << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Post: " << info.stateRoot() << "" << "
"; s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } @@ -1807,7 +1807,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 61fde605d..0d227b1ef 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -398,8 +398,8 @@ private: void doInitDAG(unsigned _n) { BlockInfo bi; - bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; + bi.number() = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 2fb2a0e67..4e1fb66ea 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -24,7 +24,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index d48b64bb1..b2c15d7ae 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,7 +1,7 @@ #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" #include "Stack.h" @@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; + case RuntimeData::Timestamp: return "block.timestamp()"; case RuntimeData::Code: return "code.ptr"; case RuntimeData::CodeSize: return "code.size"; } diff --git a/exp/main.cpp b/exp/main.cpp index 4a35068f1..0b740e526 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,8 +85,8 @@ int main() BlockInfo bi; bi.difficulty = c_genesisDifficulty; bi.gasLimit = c_genesisGasLimit; - bi.number = 1; - bi.parentHash = sha3("parentHash"); + bi.number() = 1; + bi.parentHash() = sha3("parentHash"); bytes sealedData; @@ -329,7 +329,7 @@ int main() mine(s, bc, se); bytes minedBlock = s.blockData(); - cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot(); bc.import(minedBlock, stateDB); cnote << bc; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 22da67080..7ef3dd21e 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -44,19 +44,19 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri m_sig = _header[BlockInfo::BasicFields].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); BOOST_THROW_EXCEPTION(ex); } } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 64961bc40..266f57cc8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -BlockInfo::BlockInfo(): timestamp(Invalid256) +BlockInfo::BlockInfo(): m_timestamp(Invalid256) { } @@ -45,26 +45,26 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, void BlockInfo::clear() { - parentHash = h256(); - sha3Uncles = EmptyListSHA3; - coinbaseAddress = Address(); - stateRoot = EmptyTrie; - transactionsRoot = EmptyTrie; - receiptsRoot = EmptyTrie; - logBloom = LogBloom(); - difficulty = 0; - number = 0; - gasLimit = 0; - gasUsed = 0; - timestamp = 0; - extraData.clear(); + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_coinbaseAddress = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = 0; + m_extraData.clear(); noteDirty(); } h256 const& BlockInfo::boundary() const { - if (!m_boundary && difficulty) - m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); + if (!m_boundary && m_difficulty) + m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty); return m_boundary; } @@ -81,8 +81,8 @@ h256 const& BlockInfo::hashWithout() const void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << gasLimit << gasUsed << timestamp << extraData; + _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; } h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) @@ -110,19 +110,19 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { - parentHash = _header[field = 0].toHash(RLP::VeryStrict); - sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); - coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); - stateRoot = _header[field = 3].toHash(RLP::VeryStrict); - transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); - receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); - logBloom = _header[field = 6].toHash(RLP::VeryStrict); - difficulty = _header[field = 7].toInt(); - number = _header[field = 8].toInt(); - gasLimit = _header[field = 9].toInt(); - gasUsed = _header[field = 10].toInt(); - timestamp = _header[field = 11].toInt(); - extraData = _header[field = 12].toBytes(); + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toInt(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toInt(); + m_extraData = _header[field = 12].toBytes(); } catch (Exception const& _e) { @@ -130,11 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) throw; } - if (number > ~(unsigned)0) + if (m_number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing && gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); + if (_s != CheckNothing && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -147,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); - if (transactionsRoot != expectedRoot) + if (m_transactionsRoot != expectedRoot) { MemoryDB tm; GenericTrieDB transactionsTrie(&tm); @@ -172,52 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) cdebug << toHex(t); - BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot)); + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); - if (sha3Uncles != sha3(root[2].data())) + if (m_sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } void BlockInfo::populateFromParent(BlockInfo const& _parent) { - stateRoot = _parent.stateRoot; - number = _parent.number + 1; - gasLimit = selectGasLimit(_parent); - gasUsed = 0; - difficulty = calculateDifficulty(_parent); - parentHash = _parent.hash(); + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_gasLimit = selectGasLimit(_parent); + m_gasUsed = 0; + m_difficulty = calculateDifficulty(_parent); + m_parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return c_genesisGasLimit; else // target minimum of 3141592 - if (_parent.gasLimit < c_genesisGasLimit) - return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + if (_parent.m_gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return (u256)c_genesisDifficulty; else - return max(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor))); + return max(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); } void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check timestamp is after previous timestamp. - if (parentHash) + if (m_parentHash) { - if (timestamp <= _parent.timestamp) + if (m_timestamp <= _parent.m_timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); - if (number != _parent.number + 1) + if (m_number != _parent.m_number + 1) BOOST_THROW_EXCEPTION(InvalidNumber()); } } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b00fa73fb..67a5397f4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -81,21 +81,6 @@ struct BlockInfo public: static const unsigned BasicFields = 13; - // TODO: make them all private! - h256 parentHash; - h256 sha3Uncles; - Address coinbaseAddress; - h256 stateRoot; - h256 transactionsRoot; - h256 receiptsRoot; - LogBloom logBloom; - u256 difficulty; // TODO: pull out into BlockHeader - u256 number; - u256 gasLimit; - u256 gasUsed; - u256 timestamp = Invalid256; - bytes extraData; - BlockInfo(); explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} @@ -104,23 +89,23 @@ public: static h256 headerHashFromBlock(bytesConstRef _block); static RLP extractHeader(bytesConstRef _block); - explicit operator bool() const { return timestamp != Invalid256; } + explicit operator bool() const { return m_timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { - return parentHash == _cmp.parentHash && - sha3Uncles == _cmp.sha3Uncles && - coinbaseAddress == _cmp.coinbaseAddress && - stateRoot == _cmp.stateRoot && - transactionsRoot == _cmp.transactionsRoot && - receiptsRoot == _cmp.receiptsRoot && - logBloom == _cmp.logBloom && - difficulty == _cmp.difficulty && - number == _cmp.number && - gasLimit == _cmp.gasLimit && - gasUsed == _cmp.gasUsed && - timestamp == _cmp.timestamp && - extraData == _cmp.extraData; + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_coinbaseAddress == _cmp.coinbaseAddress() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } @@ -132,6 +117,31 @@ public: u256 selectGasLimit(BlockInfo const& _parent) const; h256 const& boundary() const; + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); } + void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + + Address const& coinbaseAddress() const { return m_coinbaseAddress; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& timestamp() const { return m_timestamp; } + bytes const& extraData() const { return m_extraData; } + + u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader + /// sha3 of the header only. h256 const& hashWithout() const; h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } @@ -145,6 +155,21 @@ protected: mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + h256 m_parentHash; + h256 m_sha3Uncles; + Address m_coinbaseAddress; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + u256 m_number; + u256 m_gasLimit; + u256 m_gasUsed; + u256 m_timestamp = Invalid256; + bytes m_extraData; + + u256 m_difficulty; // TODO: pull out into BlockHeader + private: mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty @@ -152,9 +177,9 @@ private: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp; + _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); return _out; } @@ -191,7 +216,7 @@ public: // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { - if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); BlockInfoSub::verifyParent(_parent); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 499854584..05cc45280 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -124,7 +124,7 @@ static void badBlockInfo(BlockInfo const& _bi, string const& _err) ss << c_space << endl; ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_space << endl; - string bin = toString(_bi.number); + string bin = toString(_bi.number()); ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; ss << c_space << endl; ss << c_line; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 128822b80..ee483aa8b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ namespace eth h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); + m_seedHash = EthashAux::seedHash((unsigned)m_number); return m_seedHash; } @@ -72,7 +72,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_nonce(m_nonce); @@ -81,42 +81,42 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } if (_s != CheckNothing) { - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + if (m_difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) ); - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + if (m_gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) ); - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + if (m_number && m_extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size()))); } } void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) { // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + if (m_difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty)); - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); + if (m_gasLimit < c_minGasLimit || + m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor || + m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)); } void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) @@ -126,7 +126,7 @@ void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) bool Ethash::BlockHeaderRaw::preVerify() const { - if (number >= ETHASH_EPOCH_LENGTH * 2048) + if (m_number >= ETHASH_EPOCH_LENGTH * 2048) return false; bool ret = !!ethash_quick_check_difficulty( @@ -162,7 +162,7 @@ bool Ethash::BlockHeaderRaw::verify() const cwarn << "headerHash:" << hashWithout(); cwarn << "nonce:" << m_nonce; cwarn << "mixHash:" << m_mixHash; - cwarn << "difficulty:" << difficulty; + cwarn << "difficulty:" << m_difficulty; cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; @@ -290,7 +290,7 @@ public: m_farm.setWork(m_sealing); m_farm.start(m_sealer); m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number); + Ethash::ensurePrecomputed((unsigned)_bi.number()); } void onSealGenerated(std::function const& _f) override { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index c511978db..763bea417 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,7 +63,7 @@ EthashAux* EthashAux::get() uint64_t EthashAux::cacheSize(BlockInfo const& _header) { - return ethash_get_cachesize((uint64_t)_header.number); + return ethash_get_cachesize((uint64_t)_header.number()); } uint64_t EthashAux::dataSize(uint64_t _blockNumber) diff --git a/libethereum/BasicGasPricer.cpp b/libethereum/BasicGasPricer.cpp index 145d23594..b957966f8 100644 --- a/libethereum/BasicGasPricer.cpp +++ b/libethereum/BasicGasPricer.cpp @@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; h256 p = _bc.currentHash(); - m_gasPerBlock = _bc.info(p).gasLimit; + m_gasPerBlock = _bc.info(p).gasLimit(); map dist; u256 total = 0; @@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc) while (c < 1000 && p) { BlockInfo bi = _bc.info(p); - if (bi.transactionsRoot != EmptyTrie) + if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); @@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc) i++; } } - p = bi.parentHash; + p = bi.parentHash(); ++c; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aae8cbd10..b696c77bd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) { try { BlockInfo d(bytesConstRef(it->value())); - _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; + _out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; } catch (...) { cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); @@ -293,11 +293,11 @@ void BlockChain::rebuild(std::string const& _path, std::function parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1); + cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); return; } lastHash = bi.hash(); @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -461,21 +461,21 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Work out its number as the parent's number + 1 - if (!isKnown(_block.info.parentHash)) + if (!isKnown(_block.info.parentHash())) { - clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash(); // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_block.info.parentHash); + auto pd = details(_block.info.parentHash()); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_block.info.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; + auto parentBlock = block(_block.info.parentHash()); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash()); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number(); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -483,9 +483,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Check it's not crazy - if (_block.info.timestamp > (u256)time(0)) + if (_block.info.timestamp() > (u256)time(0)) { - clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } @@ -543,9 +543,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_block.info.parentHash); + details(_block.info.parentHash()); DEV_WRITE_GUARDED(x_details) - m_details[_block.info.parentHash].children.push_back(_block.info.hash()); + m_details[_block.info.parentHash()].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); @@ -554,9 +554,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp())); - extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); @@ -585,10 +585,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif - // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; h256 common; @@ -599,7 +599,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash()); route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be @@ -630,15 +630,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Collate logs into blooms. h256s alteredBlooms; { - LogBloom blockBloom = tbi.logBloom; - blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); + LogBloom blockBloom = tbi.logBloom(); + blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref())); // Pre-memoize everything we need before locking x_blocksBlooms - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) blocksBlooms(chunkId(level, index / c_bloomIndexSize)); WriteGuard l(x_blocksBlooms); - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) { unsigned i = index / c_bloomIndexSize; unsigned o = index % c_bloomIndexSize; @@ -661,23 +661,23 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& ReadGuard l1(x_blocksBlooms); for (auto const& h: alteredBlooms) extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); - extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); + extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); } // FINALLY! change our best hash. { newLastBlockHash = _block.info.hash(); - newLastBlockNumber = (unsigned)_block.info.number; + newLastBlockNumber = (unsigned)_block.info.number(); } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; #if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif } @@ -750,7 +750,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& checkBest = t.elapsed(); if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number(); cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; @@ -758,7 +758,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; cnote << " " << _block.transactions.size() << " transactions"; - cnote << " " << _block.info.gasUsed << " gas used"; + cnote << " " << _block.info.gasUsed() << " gas used"; } #endif @@ -861,7 +861,7 @@ void BlockChain::rescue(OverlayDB& _db) cout << "extras..." << flush; details(h); cout << "state..." << flush; - if (_db.exists(bi.stateRoot)) + if (_db.exists(bi.stateRoot())) break; } catch (...) {} @@ -1233,19 +1233,3 @@ State BlockChain::genesisState(OverlayDB const& _db) return ret; } - - - - - - - - - - - - - - - - diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50965f2b6..3ff85c8a6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -391,7 +391,7 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash)); + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index ed022fb75..2141c4587 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr _peer) unsigned BlockChainSync::estimatedHashes() const { BlockInfo block = host().chain().info(); - time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp(); time_t now = time(0); unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) @@ -220,9 +220,9 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); - if (bi.number > maxUnknownNumber) + if (bi.number() > maxUnknownNumber) { - maxUnknownNumber = bi.number; + maxUnknownNumber = bi.number(); maxUnknown = h; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6b400b236..c9ee4c1cf 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,8 +101,8 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.sha3Uncles = work.hash; - bi.parentHash = work.parentHash; + bi.setSha3Uncles(work.hash); + bi.setParentHash(work.parentHash); m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.sha3Uncles == work.hash) + if (it->verified.info.sha3Uncles() == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,11 +136,11 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash) { // we're next! m_verifying.pop_front(); - if (m_knownBad.count(res.verified.info.parentHash)) + if (m_knownBad.count(res.verified.info.parentHash())) { m_readySet.erase(res.verified.info.hash()); m_knownBad.insert(res.verified.info.hash()); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.sha3Uncles == work.hash) + if (i.verified.info.sha3Uncles() == work.hash) { i = move(res); goto OK; @@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() { while (!m_verifying.empty() && !m_verifying.front().blockData.empty()) { - if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + if (m_knownBad.count(m_verifying.front().verified.info.parentHash())) { m_readySet.erase(m_verifying.front().verified.info.hash()); m_knownBad.insert(m_verifying.front().verified.info.hash()); @@ -213,7 +213,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) return ImportResult::Malformed; } - clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash(); // Check block doesn't already exist first! if (m_bc->isKnown(h)) @@ -227,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // Check it's not in the future (void)_isOurs; - if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) + if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/) { - m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); + m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes()))); char buf[24]; - time_t bit = (unsigned)bi.timestamp; + time_t bit = (unsigned)bi.timestamp(); if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails - clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp() << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); + m_difficulty += bi.difficulty(); + bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash()); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. - if (m_knownBad.count(bi.parentHash)) + if (m_knownBad.count(bi.parentHash())) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash())) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; - m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash(); + m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_unknownCount++; return ImportResult::UnknownParent; @@ -268,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash(), _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_knownCount++; noteReady_WITH_LOCK(h); @@ -295,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::vector oldVerified; swap(m_verified, oldVerified); for (auto& b: oldVerified) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash())) { m_knownBad.insert(b.verified.info.hash()); m_readySet.erase(b.verified.info.hash()); @@ -321,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles())) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles(); m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); @@ -460,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; + m_drainingDifficulty += bs.verified.info.difficulty(); m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 866c9c8f9..e58e1a8c6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), + m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)), m_depth(_level) {} @@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction) // Avoid transactions that would take us beyond the block gas limit. u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) + if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit()) { - clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; - BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas())); } // Check gas cost is enough. @@ -403,7 +403,7 @@ void Executive::finalize() m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); - m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); + m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned); // Suicides... if (m_ext) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ee2078a07..64daaf5f8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -105,7 +105,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock.clear(); m_currentBlock.clear(); -// assert(m_state.root() == m_previousBlock.stateRoot); +// assert(m_state.root() == m_previousBlock.stateRoot()); paranoia("end of normal construction.", true); } @@ -123,16 +123,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& auto b = _bc.block(_h); BlockInfo bi(b); - if (bi.number) + if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + BlockInfo bip(_bc.block(bi.parentHash())); + sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. - m_ourAddress = bi.coinbaseAddress; + m_ourAddress = bi.coinbaseAddress(); Timer t; auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); @@ -338,9 +338,9 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - if (m_db.lookup(bi.stateRoot).empty()) + if (m_db.lookup(bi.stateRoot()).empty()) { - cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; + cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); @@ -357,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash()); // push back for later replay. - bi.populate(_bc.block(bi.parentHash)); // move to parent. + bi.populate(_bc.block(bi.parentHash())); // move to parent. } m_previousBlock = bi; @@ -402,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif // Check family: - BlockInfo biParent = _bc.info(_block.info.parentHash); + BlockInfo biParent = _bc.info(_block.info.parentHash()); _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -411,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif BlockInfo biGrandParent; - if (biParent.number) - biGrandParent = _bc.info(biParent.parentHash); + if (biParent.number()) + biGrandParent = _bc.info(biParent.parentHash()); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo()); + sync(_bc, _block.info.parentHash(), BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -462,17 +462,15 @@ void State::resetCurrent() m_cache.clear(); m_touched.clear(); m_currentBlock = BlockInfo(); - m_currentBlock.coinbaseAddress = m_ourAddress; - m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); - m_currentBlock.transactionsRoot = h256(); - m_currentBlock.sha3Uncles = h256(); + m_currentBlock.setCoinbaseAddress(m_ourAddress); + m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0))); m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); m_committedToMine = false; @@ -538,7 +536,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu catch (BlockGasLimitReached const& e) { bigint const& got = *boost::get_error_info(e); - if (got > m_currentBlock.gasLimit) + if (got > m_currentBlock.gasLimit()) { clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; _tq.drop(t.sha3()); @@ -583,7 +581,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number()); string ret; unsigned i = 0; @@ -604,12 +602,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == _block.info.parentHash); - assert(m_currentBlock.parentHash == _block.info.parentHash); - assert(rootHash() == m_previousBlock.stateRoot); + assert(m_previousBlock.hash() == _block.info.parentHash()); + assert(m_currentBlock.parentHash() == _block.info.parentHash()); + assert(rootHash() == m_previousBlock.stateRoot()); #endif - if (m_currentBlock.parentHash != m_previousBlock.hash()) + if (m_currentBlock.parentHash() != m_previousBlock.hash()) // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); @@ -622,7 +620,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) LastHashes lh; DEV_TIMED_ABOVE("lastHashes", 500) - lh = _bc.lastHashes((unsigned)m_previousBlock.number); + lh = _bc.lastHashes((unsigned)m_previousBlock.number()); RLP rlp(_block.block); @@ -651,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) } h256 receiptsRoot; - DEV_TIMED_ABOVE("receiptsRoot", 500) + DEV_TIMED_ABOVE(".receiptsRoot()", 500) receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) + if (receiptsRoot != m_currentBlock.receiptsRoot()) { InvalidReceiptsStateRoot ex; - ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot()); ex << errinfo_receipts(receipts); ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } - if (m_currentBlock.logBloom != logBloom()) + if (m_currentBlock.logBloom() != logBloom()) { InvalidLogBloom ex; - ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom()); ex << errinfo_receipts(receipts); BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. - u256 tdIncrease = m_currentBlock.difficulty; + u256 tdIncrease = m_currentBlock.difficulty(); // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) @@ -686,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) vector rewarded; h256Hash excluded; DEV_TIMED_ABOVE("allKin", 500) - excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; @@ -710,22 +708,22 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) + if (!_bc.isKnown(uncle.parentHash())) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + uncleParent = BlockInfo(_bc.block(uncle.parentHash())); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7) { UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } - else if (uncle.number == m_currentBlock.number) + else if (uncle.number() == m_currentBlock.number()) { UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } uncle.verifyParent(uncleParent); @@ -748,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash()) { m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot())); } - if (m_currentBlock.gasUsed != gasUsed()) + if (m_currentBlock.gasUsed() != gasUsed()) { // Rollback the trie. m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed()))); } return tdIncrease; @@ -772,7 +770,7 @@ void State::cleanup(bool _fullCommit) // Commit the new trie to disk. if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -786,7 +784,7 @@ void State::cleanup(bool _fullCommit) m_db.commit(); if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -806,7 +804,7 @@ void State::uncommitToMine() { m_cache.clear(); if (!m_transactions.size()) - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); else m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; @@ -878,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock.number != 0) + if (m_previousBlock.number() != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); - auto p = m_previousBlock.parentHash; +// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl; + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; @@ -926,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = hash256(transactionsMap); - m_currentBlock.receiptsRoot = hash256(receiptsMap); - m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); - // Apply rewards last of all. applyRewards(uncleBlockHeaders); @@ -941,12 +934,18 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // cnote << m_state; // cnote << *this; - m_currentBlock.gasUsed = gasUsed(); - m_currentBlock.stateRoot = m_state.root(); - m_currentBlock.parentHash = m_previousBlock.hash(); - m_currentBlock.extraData = _extraData; - if (m_currentBlock.extraData.size() > 32) - m_currentBlock.extraData.resize(32); + m_currentBlock.setLogBloom(logBloom()); + m_currentBlock.setGasUsed(gasUsed()); + m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root()); + + m_currentBlock.setParentHash(m_previousBlock.hash()); + m_currentBlock.setExtraData(_extraData); + if (m_currentBlock.extraData().size() > 32) + { + auto ed = m_currentBlock.extraData(); + ed.resize(32); + m_currentBlock.setExtraData(ed); + } m_committedToMine = true; } @@ -967,13 +966,13 @@ bool State::sealBlock(bytesConstRef _header) ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); - cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; + cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")"; // TODO: move into Sealer StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), "", // Can't give the nonce here. "", //TODO: chain head hash here ?? - m_currentBlock.parentHash.abridged() + m_currentBlock.parentHash().abridged() ); // Quickly reset the transactions. @@ -1270,7 +1269,7 @@ State State::fromPending(unsigned _i) const ret.m_cache.clear(); _i = min(_i, m_transactions.size()); if (!_i) - ret.m_state.setRoot(m_previousBlock.stateRoot); + ret.m_state.setRoot(m_previousBlock.stateRoot()); else ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) @@ -1287,10 +1286,10 @@ void State::applyRewards(vector const& _uncleBlockHeaders) u256 r = m_blockReward; for (auto const& i: _uncleBlockHeaders) { - addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8); + addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8); r += m_blockReward / 32; } - addBalance(m_currentBlock.coinbaseAddress, r); + addBalance(m_currentBlock.coinbaseAddress(), r); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) diff --git a/libethereum/State.h b/libethereum/State.h index 805215ee5..e2bda6f24 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } + u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); } /// Check if the address is in use. bool addressInUse(Address _address) const; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..a5c45af26 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -83,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry ): LogEntry(_le), blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), + blockNumber((BlockNumber)_bi.number()), transactionHash(_th), transactionIndex(_ti), logIndex(_li), @@ -205,7 +205,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } + h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2b2ada0ae..f95481c54 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress()); break; case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); + m_stack.push_back(_ext.currentBlock.timestamp()); break; case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); + m_stack.push_back(_ext.currentBlock.number()); break; case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); + m_stack.push_back(_ext.currentBlock.difficulty()); break; case Instruction::GASLIMIT: - m_stack.push_back(_ext.currentBlock.gasLimit); + m_stack.push_back(_ext.currentBlock.gasLimit()); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libtestutils/BlockChainLoader.cpp b/libtestutils/BlockChainLoader.cpp index e6c47e2fe..7e08243af 100644 --- a/libtestutils/BlockChainLoader.cpp +++ b/libtestutils/BlockChainLoader.cpp @@ -36,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) // load genesisBlock m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); - assert(m_state.rootHash() == m_bc->info().stateRoot); + assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks for (auto const& block: _json["blocks"]) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 15d39bded..fae12708c 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -88,18 +88,18 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) if (_bi) { res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["parentHash"] = toJS(_bi.parentHash()); + res["sha3Uncles"] = toJS(_bi.sha3Uncles()); + res["miner"] = toJS(_bi.coinbaseAddress()); + res["stateRoot"] = toJS(_bi.stateRoot()); + res["transactionsRoot"] = toJS(_bi.transactionsRoot()); res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); + res["number"] = toJS(_bi.number()); res["gasUsed"] = toJS(_bi.gasUsed); res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["logsBloom"] = toJS(_bi.logBloom); + res["timestamp"] = toJS(_bi.timestamp()); + res["extraData"] = toJS(_bi.extraData()); + res["logsBloom"] = toJS(_bi.logBloom()); res["target"] = toJS(_bi.boundary()); // TODO: move into ProofOfWork. @@ -140,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number())); } return res; } @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()); + res["stateRoot"] = toJS(_t.stateRoot()()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b43c4db51..bae980a7e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -151,12 +151,12 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); m_environment.currentBlock.number = toInt(_o["currentNumber"]); m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 9ee93779e..7dbc5c91e 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(blocks) u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString()); h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString())); h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); - ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom); - ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress); + ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); + ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), - _blockInfo.extraData.begin(), - _blockInfo.extraData.end() + _blockInfo.extraData().begin(), + _blockInfo.extraData().end() ); ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); @@ -132,11 +132,11 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); - ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp); - ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles); + ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); + ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; BlockInfo blockInfo = _client.blockInfo(blockHash); diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 20f60618f..cf44dfd9f 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -66,7 +66,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,9 +76,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot = trueState.rootHash(); + biGenesisBlock.stateRoot() = trueState.rootHash(); else - TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -125,7 +125,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TransientDirectory td_stateDB, td_bc; BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -225,7 +225,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); updatePoW(current_BlockHeader); } @@ -302,7 +302,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (o.count("expect") > 0) { stateOptionsMap expectStateMap; - State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); @@ -313,7 +313,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section - State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); }//_fillin @@ -374,19 +374,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); @@ -551,7 +551,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp = (u256)time(0); + uncleBlockFromFields.timestamp() = (u256)time(0); cnote << "uncle block n = " << toString(uncleBlockFromFields.number); if (_vBiBlocks.size() > 2) { @@ -568,15 +568,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash; - uncleBlockFromFields.stateRoot = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot; + uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); + uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); if (overwrite == "timestamp") { - uncleBlockFromFields.timestamp = toInt(uncleHeaderObj["timestamp"]); + uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); } } @@ -660,19 +660,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { BlockInfo tmp = _header; if (ho.count("parentHash")) - tmp.parentHash = h256(ho["parentHash"].get_str()); + tmp.parentHash() = h256(ho["parentHash"].get_str()); if (ho.count("uncleHash")) - tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); if (ho.count("coinbase")) - tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); if (ho.count("stateRoot")) - tmp.stateRoot = h256(ho["stateRoot"].get_str()); + tmp.stateRoot() = h256(ho["stateRoot"].get_str()); if (ho.count("transactionsTrie")) - tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); if (ho.count("receiptTrie")) - tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); if (ho.count("bloom")) - tmp.logBloom = LogBloom(ho["bloom"].get_str()); + tmp.logBloom() = LogBloom(ho["bloom"].get_str()); if (ho.count("difficulty")) tmp.difficulty = toInt(ho["difficulty"]); if (ho.count("number")) @@ -682,9 +682,9 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) if (ho.count("gasUsed")) tmp.gasUsed = toInt(ho["gasUsed"]); if (ho.count("timestamp")) - tmp.timestamp = toInt(ho["timestamp"]); + tmp.timestamp() = toInt(ho["timestamp"]); if (ho.count("extraData")) - tmp.extraData = importByteArray(ho["extraData"].get_str()); + tmp.extraData() = importByteArray(ho["extraData"].get_str()); // find new valid nonce if (tmp != _header && tmp.difficulty) @@ -751,19 +751,19 @@ mArray writeTransactionsToJson(Transactions const& txs) mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) { - _o["parentHash"] = toString(_bi.parentHash); - _o["uncleHash"] = toString(_bi.sha3Uncles); - _o["coinbase"] = toString(_bi.coinbaseAddress); - _o["stateRoot"] = toString(_bi.stateRoot); - _o["transactionsTrie"] = toString(_bi.transactionsRoot); - _o["receiptTrie"] = toString(_bi.receiptsRoot); - _o["bloom"] = toString(_bi.logBloom); + _o["parentHash"] = toString(_bi.parentHash()); + _o["uncleHash"] = toString(_bi.sha3Uncles()); + _o["coinbase"] = toString(_bi.coinbaseAddress()); + _o["stateRoot"] = toString(_bi.stateRoot()); + _o["transactionsTrie"] = toString(_bi.transactionsRoot()); + _o["receiptTrie"] = toString(_bi.receiptsRoot()); + _o["bloom"] = toString(_bi.logBloom()); _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); - _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); + _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); _o["hash"] = toString(_bi.hash()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 02ff4517a..2d5a2faa6 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index fdfb180fb..28b2e43ab 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -83,10 +83,10 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st mObject FakeExtVM::exportEnv() { mObject ret; - ret["previousHash"] = toString(currentBlock.parentHash); + ret["previousHash"] = toString(currentBlock.parentHash()); ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); - ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp, HexPrefix::Add, 1); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); return ret; @@ -102,13 +102,13 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash = h256(_o["previousHash"].get_str()); + currentBlock.parentHash() = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } mObject FakeExtVM::exportState() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 9f806347e..be44ea009 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1187,7 +1187,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " return block.timestamp() == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/third/MainWin.cpp b/third/MainWin.cpp index f2a90cc0b..a3b05572f 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From 7962a50a39ff48c1f435b5c8399d0fb748c3ae41 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:34:11 +0200 Subject: [PATCH 030/113] Minor fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ec37302a2..357926d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -98,7 +98,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + bc().rescue(m_stateDB); m_gp->update(bc()); From 016ce6964fc8e2e64c717b3184ba07532c88191d Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 09:46:22 +0200 Subject: [PATCH 031/113] copy evmjit dll to output on windows --- CMakeLists.txt | 10 ++++++---- alethzero/CMakeLists.txt | 2 +- eth/CMakeLists.txt | 2 +- evmjit/libevmjit/CMakeLists.txt | 1 - 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 271f3ed65..48f1efee0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -368,6 +368,10 @@ if (EVMJIT) endif() set(EVMJIT_CPP TRUE) # include CPP-JIT connector add_subdirectory(evmjit) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + get_property(EVMJIT_DLLS_LOCAL TARGET "evmjit" PROPERTY LOCATION) + set(EVMJIT_DLLS optimized ${EVMJIT_DLLS_LOCAL} debug ${EVMJIT_DLLS_LOCAL}) + endif() endif() if (TOOLS OR GUI OR SOLIDITY OR NCURSES OR TESTS) @@ -409,10 +413,8 @@ if (JSCONSOLE) add_subdirectory(ethconsole) endif () -if (NOT WIN32) - add_definitions(-DETH_HAVE_SECP256K1) - add_subdirectory(secp256k1) -endif () +add_definitions(-DETH_HAVE_SECP256K1) +add_subdirectory(secp256k1) add_subdirectory(libscrypt) add_subdirectory(libdevcrypto) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 8bc349fb2..6f9dc59b3 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -72,5 +72,5 @@ if (SERPENT) endif() # eth_install_executable is defined in cmake/EthExecutableHelper.cmake -eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS) +eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS EVMJIT_DLLS) diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index d317be28a..dd4d61cd2 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -42,7 +42,7 @@ if (JSCONSOLE) endif() if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) - eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) + eth_copy_dlls("${EXECUTABLE}" MHD_DLLS EVMJIT_DLLS) endif() if (APPLE) diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index 80108e15b..a41c7b365 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -29,7 +29,6 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") endif() - set(EVMJIT_VERSION "0.0.0") set(EVMJIT_VERSION_MAJOR 0) set(EVMJIT_VERSION_MINOR 0) From 659858f6c0045f76507916b8d5d06fe84663eab2 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 11:43:23 +0200 Subject: [PATCH 032/113] fixed build --- evmjit/libevmjit-cpp/JitVM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 4e1fb66ea..d96da87c1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -42,10 +42,10 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); - m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); - m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); - m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); + m_data.difficulty = eth2jit(_ext.currentBlock.difficulty()); + m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit()); + m_data.number = static_cast(_ext.currentBlock.number()); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); From 63ef6a74f9ae708ade1f840925b5c70cf47c37a4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 12:28:00 +0200 Subject: [PATCH 033/113] reverted libsecp256k1 changes --- CMakeLists.txt | 10 ++++++---- evmjit/libevmjit/CMakeLists.txt | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48f1efee0..4eade560f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,8 +369,8 @@ if (EVMJIT) set(EVMJIT_CPP TRUE) # include CPP-JIT connector add_subdirectory(evmjit) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - get_property(EVMJIT_DLLS_LOCAL TARGET "evmjit" PROPERTY LOCATION) - set(EVMJIT_DLLS optimized ${EVMJIT_DLLS_LOCAL} debug ${EVMJIT_DLLS_LOCAL}) + get_property(EVMJIT_DLLS_LOCAL TARGET "evmjit" PROPERTY LOCATION) + set(EVMJIT_DLLS optimized ${EVMJIT_DLLS_LOCAL} debug ${EVMJIT_DLLS_LOCAL}) endif() endif() @@ -413,8 +413,10 @@ if (JSCONSOLE) add_subdirectory(ethconsole) endif () -add_definitions(-DETH_HAVE_SECP256K1) -add_subdirectory(secp256k1) +if (NOT WIN32) + add_definitions(-DETH_HAVE_SECP256K1) + add_subdirectory(secp256k1) +endif () add_subdirectory(libscrypt) add_subdirectory(libdevcrypto) diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index a41c7b365..80108e15b 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -29,6 +29,7 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") endif() + set(EVMJIT_VERSION "0.0.0") set(EVMJIT_VERSION_MAJOR 0) set(EVMJIT_VERSION_MINOR 0) From 0431a97ecbf3588bbefa9c6c651658dfb0bc0636 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 16:45:23 +0200 Subject: [PATCH 034/113] mix working --- CMakeLists.txt | 28 +++++++------- alethzero/MainWin.cpp | 53 ++++++++++++++------------- alethzero/MiningView.cpp | 4 +- alethzero/MiningView.h | 4 +- exp/CMakeLists.txt | 4 +- libethereum/BlockChain.cpp | 1 - libtestutils/BlockChainLoader.cpp | 3 +- libtestutils/StateLoader.cpp | 2 +- libtestutils/StateLoader.h | 2 + libweb3jsonrpc/JsonHelper.cpp | 8 ++-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libwebthree/WebThree.cpp | 2 +- mix/ClientModel.cpp | 4 +- mix/MixClient.cpp | 36 +++++++++--------- mix/MixClient.h | 36 +++++++++++++++--- 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 421dd1bb7..271f3ed65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) -# add_subdirectory(libweb3jsonrpc) + add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) -# add_subdirectory(libjsengine) -# add_subdirectory(libjsconsole) -# add_subdirectory(ethconsole) + add_subdirectory(libjsengine) + add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -434,31 +434,31 @@ add_subdirectory(libethcore) if (GENERAL) add_subdirectory(libevm) add_subdirectory(libethereum) -# add_subdirectory(libwebthree) + add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) -# add_subdirectory(ethminer) + add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) -# add_subdirectory(ethkey) + add_subdirectory(ethkey) endif () if (TESTS) -# add_subdirectory(libtestutils) -# add_subdirectory(test) + add_subdirectory(libtestutils) + add_subdirectory(test) if (JSONRPC) -# add_subdirectory(ethrpctest) + add_subdirectory(ethrpctest) endif () endif () if (TOOLS) -# add_subdirectory(rlp) -# add_subdirectory(abi) -# add_subdirectory(ethvm) -# add_subdirectory(eth) + add_subdirectory(rlp) + add_subdirectory(abi) + add_subdirectory(ethvm) + add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ad8f5528c..181772ddb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,9 +189,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; - auto block = CanonBlockChain::createGenesisBlock(); - cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl; @@ -208,13 +208,14 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); @@ -1124,7 +1125,7 @@ void Main::refreshMining() QString t; if (gp.first != EthashAux::NotGenerating) t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second); - MiningProgress p = ethereum()->miningProgress(); + WorkingProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining")); if (ethereum()->isMining() && p.hashes > 0) { @@ -1629,7 +1630,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1699,7 +1700,7 @@ void Main::on_blocks_currentItemChanged() auto details = ethereum()->blockChain().details(h); auto blockData = ethereum()->blockChain().block(h); auto block = RLP(blockData); - BlockInfo info(blockData); + Ethash::BlockHeader info(blockData); stringstream s; @@ -1709,21 +1710,21 @@ void Main::on_blocks_currentItemChanged() time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; - s << "

#" << info.number; + s << "

#" << info.number(); s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
"; s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; - s << "
Mix hash: " << info.mixHash << "" << "
"; - s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; - s << "
Difficulty: " << info.difficulty << "" << "
"; - if (info.number) + s << "
Mix hash: " << info.mixHash() << "" << "
"; + s << "
Nonce: " << info.nonce() << "" << "
"; + s << "
Hash w/o nonce: " << info.hashWithout() << "" << "
"; + s << "
Difficulty: " << info.difficulty() << "" << "
"; + if (info.number()) { - auto e = EthashAux::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce()); + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash() << "" << "
"; } else @@ -1740,19 +1741,19 @@ void Main::on_blocks_currentItemChanged() s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { - BlockInfo uncle = BlockInfo::fromHeader(u.data()); + Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; s << line << "Parent: " << uncle.parentHash() << "" << ""; - s << line << "Number: " << uncle.number << "" << ""; + s << line << "Number: " << uncle.number() << "" << ""; s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; - s << line << "Mix hash: " << uncle.mixHash << "" << ""; - s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Mix hash: " << uncle.mixHash() << "" << ""; + s << line << "Nonce: " << uncle.nonce() << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; - s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = EthashAux::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; + s << line << "Difficulty: " << uncle.difficulty() << "" << ""; + auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce()); + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash()) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; @@ -1764,7 +1765,7 @@ void Main::on_blocks_currentItemChanged() unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } s << "
Post: " << info.stateRoot() << "" << "
"; @@ -1807,7 +1808,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index e020408ea..fb9de0346 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MiningProgress; +using dev::eth::WorkingProgress; // functions using dev::toString; @@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MiningProgress const& _p) +void MiningView::appendStats(list const& _i, WorkingProgress const& _p) { (void)_p; if (_i.empty()) diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 65b9f2ec9..ae81a7cc4 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); + void appendStats(std::list const& _l, dev::eth::WorkingProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MiningProgress m_progress; + dev::eth::WorkingProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index b9f477385..0e19ac84d 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -21,10 +21,10 @@ if (READLINE_FOUND) endif() if (JSONRPC) -# target_link_libraries(${EXECUTABLE} web3jsonrpc) + target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -#target_link_libraries(${EXECUTABLE} webthree) +target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b696c77bd..03ab1b46a 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -137,7 +137,6 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map #include "BlockChainLoader.h" #include "StateLoader.h" #include "Common.h" @@ -35,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) m_state = sl.state(); // load genesisBlock - m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); + m_bc.reset(new FullBlockChain(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill)); assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks diff --git a/libtestutils/StateLoader.cpp b/libtestutils/StateLoader.cpp index 235f1c573..cd5c37e96 100644 --- a/libtestutils/StateLoader.cpp +++ b/libtestutils/StateLoader.cpp @@ -27,7 +27,7 @@ using namespace dev::eth; using namespace dev::test; StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): - m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty) + m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty) { for (string const& name: _json.getMemberNames()) { diff --git a/libtestutils/StateLoader.h b/libtestutils/StateLoader.h index 47eb26900..c66f53148 100644 --- a/libtestutils/StateLoader.h +++ b/libtestutils/StateLoader.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace dev { @@ -38,6 +39,7 @@ class StateLoader public: StateLoader(Json::Value const& _json, std::string const& _dbPath); eth::State const& state() const { return m_state; } + eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; } private: eth::State m_state; diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index fae12708c..54fde52e8 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -93,10 +93,10 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["miner"] = toJS(_bi.coinbaseAddress()); res["stateRoot"] = toJS(_bi.stateRoot()); res["transactionsRoot"] = toJS(_bi.transactionsRoot()); - res["difficulty"] = toJS(_bi.difficulty); + res["difficulty"] = toJS(_bi.difficulty()); res["number"] = toJS(_bi.number()); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); + res["gasUsed"] = toJS(_bi.gasUsed()); + res["gasLimit"] = toJS(_bi.gasLimit()); res["timestamp"] = toJS(_bi.timestamp()); res["extraData"] = toJS(_bi.extraData()); res["logsBloom"] = toJS(_bi.logBloom()); @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()()); + res["stateRoot"] = toJS(_t.stateRoot()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 3aff9cf23..bf49d3322 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str return true; } -dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +dev::eth::BlockChain const& WebThreeStubServer::bc() const { return m_web3.ethereum()->blockChain(); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4d545c90e..2860f852b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -34,7 +34,7 @@ namespace eth { class KeyManager; class TrivialGasPricer; -class CanonBlockChain; +class BlockChain; class BlockQueue; } @@ -89,7 +89,7 @@ private: private: h256 blockHash(std::string const& _blockNumberOrHash) const; - dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockChain const& bc() const; dev::eth::BlockQueue const& bq() const; dev::WebThreeDirect& m_web3; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 3c1dea40f..7889b5935 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect( Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) { - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); + m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr(), _dbPath, _we, 0)); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 90ff19feb..5c5f2f4cd 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); stringstream strGas; - strGas << blockInfo.gasUsed; + strGas << blockInfo.gasUsed(); stringstream strNumber; - strNumber << blockInfo.number; + strNumber << blockInfo.number(); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ea4686601..eef6ad6ec 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -24,12 +24,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include "Exceptions.h" using namespace std; @@ -45,22 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho namespace { +} -struct MixPow //dummy POW +MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot): + FullBlockChain(createGenesisBlock(_stateRoot), std::unordered_map(), _path, WithExisting::Kill) { - typedef int Solution; - static bool verify(BlockInfo const&) { return true; } -}; - } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(15) + block.appendList(13) << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); + << std::string(); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -78,7 +77,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,12 +89,13 @@ void MixClient::resetState(std::unordered_map const& _accounts SecureTrieDB accountState(&m_stateDB); accountState.init(); - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + dev::eth::commit(_accounts, accountState); h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); + State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + s.sync(bc()); + m_state = s; m_startState = m_state; WriteGuard lx(x_executions); m_executions.clear(); @@ -275,11 +274,14 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + + NoProof::BlockHeader h(m_state.info()); + RLPStream header; + h.streamRLP(header); + m_state.sealBlock(header.out()); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; } ExecutionResult MixClient::lastExecution() const @@ -383,9 +385,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MiningProgress MixClient::miningProgress() const +eth::WorkingProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::WorkingProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..279692de5 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,13 +33,40 @@ namespace dev { + namespace mix { -class MixBlockChain: public dev::eth::BlockChain +class NoProof +{ + class BlockHeaderRaw: public dev::eth::BlockInfo + { + public: + static const unsigned SealFields = 0; + + protected: + BlockHeaderRaw() = default; + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; } + void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; } + void streamRLPFields(RLPStream& _s) const { (void) _s; } + }; + +public: + + static std::string name() { return "NoProof"; } + static unsigned revision() { return 0; } + using BlockHeader = dev::eth::BlockHeaderPolished; + +private: + static AddressHash s_authorities; +}; + +class MixBlockChain: public dev::eth::FullBlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {} + MixBlockChain(std::string const& _path, h256 _stateRoot); static bytes createGenesisBlock(h256 _stateRoot); }; @@ -67,9 +95,7 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MiningProgress miningProgress() const override; - eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } - bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } + eth::WorkingProgress miningProgress() const override; virtual void flushTransactions() override {} /// @returns the last mined block information From 907ea3c8002545e4a9ccdee0f6d588dcbd2e9f85 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 18:11:08 +0200 Subject: [PATCH 035/113] started tests refactoring --- libethcore/Common.h | 3 ++- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 9 +++++---- libethereum/BlockQueue.cpp | 2 +- libethereum/Client.cpp | 3 +-- mix/MixClient.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libethcore/dagger.cpp | 4 ++-- test/libethereum/ClientBase.cpp | 14 +++++++------- test/libethereum/genesis.cpp | 6 +++--- test/libethereum/stateOriginal.cpp | 5 +++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 5c0a0cc79..116e1d5ed 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -130,9 +130,10 @@ struct ImportRequirements TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, None = 0 }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 03ab1b46a..8a654fa51 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 3ff85c8a6..811da8609 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -118,12 +118,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -391,7 +391,8 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash())); + if ((_ir & ImportRequirements::Parent) != 0) + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c9ee4c1cf..d0ca34b1c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); } catch (...) { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 357926d03..d43f240b7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -84,10 +84,9 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database // until after the construction. m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); - m_preMine = State(m_stateDB); - m_postMine = State(m_stateDB); // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. m_preMine = bc().genesisState(m_stateDB); + m_postMine = m_preMine; m_bq.setChain(bc()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index eef6ad6ec..67f2a2507 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -279,7 +279,7 @@ void MixClient::mine() RLPStream header; h.streamRLP(header); m_state.sealBlock(header.out()); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bae980a7e..30f323369 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,7 +63,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 061b5ae79..8d4cba933 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); - BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); + BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); BOOST_REQUIRE_EQUAL(nonce, header.nonce); unsigned cacheSize(o["cache_size"].get_int()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 7dbc5c91e..a426ff53f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -119,21 +119,21 @@ BOOST_AUTO_TEST_CASE(blocks) h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); - ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); + ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty()); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), _blockInfo.extraData().begin(), _blockInfo.extraData().end() ); - ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); - ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); + ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit()); + ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed()); ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash()); - ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); - ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); - ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); + ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash()); + ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce()); + ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number()); ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 2d5a2faa6..39997572f 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,9 +60,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e3f8ac29f..163c89e50 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ BOOST_AUTO_TEST_CASE(Complex) Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; + OverlayDB stateDB = State::openDB(h256()); + CanonBlockChain bc; cout << bc; State s = bc.genesisState(stateDB); From 9d8f9e3517f8e96ad10286a8ba7cf773e04bf39a Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 20:53:58 +0200 Subject: [PATCH 036/113] eth working --- eth/main.cpp | 2 +- ethminer/MinerAux.h | 26 ++++++++++++-------------- libethcore/BlockInfo.h | 1 + libethereum/Client.h | 6 +++++- test/TestHelper.cpp | 17 ++++++++++++----- test/libethcore/dagger.cpp | 6 +++--- test/libethereum/ClientBase.cpp | 4 ++-- test/libethereum/gaspricer.cpp | 3 ++- test/libevm/vm.cpp | 10 +++++----- 9 files changed, 43 insertions(+), 32 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 8bbec9f00..4a8501a97 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1311,7 +1311,7 @@ int main(int argc, char** argv) { try { - CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); } catch (...) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 0d227b1ef..01083012f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -397,17 +397,16 @@ public: private: void doInitDAG(unsigned _n) { - BlockInfo bi; - bi.number() = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; - Ethash::prep(bi); + h256 seedHash = EthashAux::seedHash(_n); + cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl; + EthashAux::full(seedHash, true); exit(0); } void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) { - BlockInfo genesis; - genesis.difficulty = 1 << 18; + Ethash::BlockHeader genesis; + genesis.setDifficulty(1 << 18); cdebug << genesis.boundary(); GenericFarm f; @@ -417,17 +416,16 @@ private: cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; - Ethash::prep(genesis); + genesis.prep(); - genesis.difficulty = u256(1) << 63; - genesis.noteDirty(); + genesis.setDifficulty(u256(1) << 63); f.setWork(genesis); if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); - map results; + map results; uint64_t mean = 0; uint64_t innerMean = 0; for (unsigned i = 0; i <= _trials; ++i) @@ -488,9 +486,9 @@ private: Farm rpc(client); GenericFarm f; if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 67a5397f4..c310b3dd9 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -128,6 +128,7 @@ public: void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } Address const& coinbaseAddress() const { return m_coinbaseAddress; } h256 const& stateRoot() const { return m_stateRoot; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 73609bd71..4523d324b 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -77,7 +77,7 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); * @brief Main API hub for interfacing with Ethereum. * Not to be used directly - subclass. */ -class Client: public ClientBase, Worker +class Client: public ClientBase, protected Worker { public: /// New-style Constructor. @@ -342,6 +342,8 @@ public: init(_host, _dbPath, _forceAction, _networkId); } + virtual ~SpecialisedClient() { stopWorking(); } + /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } @@ -365,6 +367,8 @@ public: u256 _networkId = 0 ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + virtual ~EthashClient() { stopWorking(); } + /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. virtual std::tuple getEthashWork() override; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 30f323369..c29788b9f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -63,11 +64,17 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + Ethash::BlockHeader header(s.info); + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { - return completed = s.completeMine(sol); + header.m_mixHash = sol.mixHash; + header.m_nonce = sol.nonce; + RLPStream ret; + header.streamRLP(ret); + s.sealBlock(ret); + return true; }); f.setWork(s.info()); f.startCPU(); @@ -77,9 +84,9 @@ void mine(State& s, BlockChain const& _bc) void mine(BlockInfo& _bi) { - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { _bi.proof = sol; return completed = true; diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 8d4cba933..c3cd75b0d 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(basic_test) h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); - BOOST_REQUIRE_EQUAL(nonce, header.nonce); + BOOST_REQUIRE_EQUAL(nonce, header.nonce()); unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - EthashProofOfWork::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header.seedHash(), header.hashWithout(), header.nonce()); BOOST_REQUIRE_EQUAL(r.value, result); - BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); + BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash()); } } diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index a426ff53f..f9d83e9c6 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber); // blockInfo - auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void + auto compareBlockInfos = [](Json::Value const& _b, Ethash::BlockHeader _blockInfo) -> void { LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString())); Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString())); @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - BlockInfo blockInfo = _client.blockInfo(blockHash); + Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index ce49a4a20..050ab2d25 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer) std::shared_ptr gp(new TrivialGasPricer); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); - gp->update(BlockChain(bytes(), TransientDirectory().path(), WithExisting::Kill)); + gp->update(FullBlockChain(bytes(), StateDefinition(), TransientDirectory().path(), WithExisting::Kill)); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 28b2e43ab..badabd70c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number()), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -84,11 +84,11 @@ mObject FakeExtVM::exportEnv() { mObject ret; ret["previousHash"] = toString(currentBlock.parentHash()); - ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); + ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1); ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); - ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); - ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); + ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1); + ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1); return ret; } @@ -107,7 +107,7 @@ void FakeExtVM::importEnv(mObject& _o) lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } From e7f34beb45516759120bbc89cbc4f280a9d479f1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 23:05:29 +0200 Subject: [PATCH 037/113] fixed eth_copy_dlls reverted libsecp256k1 changes --- CMakeLists.txt | 8 +++++--- cmake/EthExecutableHelper.cmake | 14 ++++++++++---- evmjit/libevmjit/CMakeLists.txt | 1 + 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48f1efee0..ceae8554c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,7 +369,7 @@ if (EVMJIT) set(EVMJIT_CPP TRUE) # include CPP-JIT connector add_subdirectory(evmjit) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - get_property(EVMJIT_DLLS_LOCAL TARGET "evmjit" PROPERTY LOCATION) + set(EVMJIT_DLLS_LOCAL $) set(EVMJIT_DLLS optimized ${EVMJIT_DLLS_LOCAL} debug ${EVMJIT_DLLS_LOCAL}) endif() endif() @@ -413,8 +413,10 @@ if (JSCONSOLE) add_subdirectory(ethconsole) endif () -add_definitions(-DETH_HAVE_SECP256K1) -add_subdirectory(secp256k1) +if (NOT WIN32) + add_definitions(-DETH_HAVE_SECP256K1) + add_subdirectory(secp256k1) +endif () add_subdirectory(libscrypt) add_subdirectory(libdevcrypto) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 1d1cb887b..1fa02bb40 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -43,11 +43,11 @@ macro(eth_add_executable EXECUTABLE) endmacro() -macro(eth_copy_dlls EXECUTABLE DLLS) +macro(eth_copy_dll EXECUTABLE DLL) # dlls must be unsubstitud list variable (without ${}) in format # optimized;path_to_dll.dll;debug;path_to_dlld.dll - list(GET ${DLLS} 1 DLL_RELEASE) - list(GET ${DLLS} 3 DLL_DEBUG) + list(GET ${DLL} 1 DLL_RELEASE) + list(GET ${DLL} 3 DLL_DEBUG) add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS @@ -59,6 +59,12 @@ macro(eth_copy_dlls EXECUTABLE DLLS) ) endmacro() +macro(eth_copy_dlls EXECUTABLE) + foreach(dll ${ARGN}) + eth_copy_dll(${EXECUTABLE} ${dll}) + endforeach(dll) +endmacro() + # # this function requires the following variables to be specified: # ETH_DEPENDENCY_INSTALL_DIR @@ -124,7 +130,7 @@ macro(eth_install_executable EXECUTABLE) #copy additional dlls foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS}) - eth_copy_dlls(${EXECUTABLE} ${dll}) + eth_copy_dll(${EXECUTABLE} ${dll}) endforeach(dll) install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Debug" diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index a41c7b365..80108e15b 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -29,6 +29,7 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") endif() + set(EVMJIT_VERSION "0.0.0") set(EVMJIT_VERSION_MAJOR 0) set(EVMJIT_VERSION_MINOR 0) From a04ba152e54ace6c46a2bd5043a318d776d55403 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jul 2015 18:59:19 -0700 Subject: [PATCH 038/113] Modularise nonce, mix hash and seed hash. --- alethzero/MainWin.cpp | 4 +-- ethminer/MinerAux.h | 10 +++---- exp/main.cpp | 2 +- libethcore/BlockInfo.cpp | 45 +++++++++++++----------------- libethcore/BlockInfo.h | 26 +++++++++--------- libethcore/Common.cpp | 5 ++-- libethcore/Common.h | 1 + libethcore/Ethash.cpp | 52 ++++++++++++++++++++++++++++------- libethcore/Ethash.h | 16 +++++++++-- libethcore/EthashAux.cpp | 7 ++++- libethcore/EthashAux.h | 2 +- libethcore/ProofOfWork.h | 1 - libethereum/BlockChain.cpp | 8 +++--- libethereum/BlockQueue.cpp | 12 ++++---- libethereum/State.cpp | 8 +++--- libethereum/State.h | 4 +-- libweb3jsonrpc/JsonHelper.cpp | 7 +++-- mix/MixClient.cpp | 1 - test/TestHelper.cpp | 2 +- 19 files changed, 128 insertions(+), 85 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e48b58283..4655240e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1718,7 +1718,7 @@ void Main::on_blocks_currentItemChanged() s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { @@ -1749,7 +1749,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ff28132b1..5c6112743 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -254,17 +254,17 @@ public: bi.difficulty = u256(m); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bi.proof.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; exit(0); } catch (...) @@ -382,7 +382,7 @@ private: { BlockInfo bi; bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/exp/main.cpp b/exp/main.cpp index 88608f8cf..9884bd0e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -197,7 +197,7 @@ int main() bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, bi); + bi.proof = sol; return completed = true; }); f.setWork(bi); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index fec5b4678..c7acd9091 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -26,7 +26,6 @@ #include #include #include "EthashAux.h" -#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -57,22 +56,21 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - mixHash = h256(); - nonce = Nonce(); - m_hash = m_seedHash = h256(); + proof = ProofOfWork::Solution(); + m_proofCache = ProofOfWork::HeaderCache(); + m_hash = h256(); } -h256 const& BlockInfo::seedHash() const +ProofOfWork::HeaderCache const& BlockInfo::proofCache() const { - if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); - return m_seedHash; + ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); + return m_proofCache; } h256 const& BlockInfo::hash() const { if (!m_hash) - m_hash = headerHash(WithNonce); + m_hash = headerHash(WithProof); return m_hash; } @@ -90,20 +88,20 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const return ret; } -h256 BlockInfo::headerHash(IncludeNonce _n) const +h256 BlockInfo::headerHash(IncludeProof _n) const { RLPStream s; streamRLP(s, _n); return sha3(s.out()); } -void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const +void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const { - _s.appendList(_n == WithNonce ? 15 : 13) + _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithNonce) - _s << mixHash << nonce; + if (_n == WithProof) + proof.streamRLP(_s); } h256 BlockInfo::headerHash(bytesConstRef _block) @@ -116,12 +114,12 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); - m_seedHash = h256(); + m_proofCache = ProofOfWork::HeaderCache(); int field = 0; try { - if (_header.itemCount() != 15) + if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); @@ -136,8 +134,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - mixHash = _header[field = 13].toHash(RLP::VeryStrict); - nonce = _header[field = 14].toHash(RLP::VeryStrict); + proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -152,22 +149,18 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ProofOfWork::composeException(ex, *this); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); - ex << errinfo_seedHash(seedHash()); ex << errinfo_target(boundary()); - ex << errinfo_mixHash(mixHash); - Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce); - ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); BOOST_THROW_EXCEPTION(ex); } else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); + ProofOfWork::composeExceptionPre(ex, *this); BOOST_THROW_EXCEPTION(ex); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 79c12ebb4..b77c47c6b 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -24,16 +24,17 @@ #include #include #include "Common.h" +#include "ProofOfWork.h" namespace dev { namespace eth { -enum IncludeNonce +enum IncludeProof { - WithoutNonce = 0, - WithNonce = 1 + WithoutProof = 0, + WithProof = 1 }; enum Strictness @@ -82,8 +83,7 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - h256 mixHash; - Nonce nonce; + typename ProofOfWork::Solution proof; BlockInfo(); explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} @@ -112,14 +112,13 @@ public: gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && extraData == _cmp.extraData && - mixHash == _cmp.mixHash && - nonce == _cmp.nonce; + proof == _cmp.proof; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } void clear(); - void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); } + void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); @@ -130,16 +129,17 @@ public: u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - h256 const& seedHash() const; + ProofOfWork::HeaderCache const& proofCache() const; h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeNonce _n) const; - void streamRLP(RLPStream& _s, IncludeNonce _n) const; + h256 headerHash(IncludeProof _n) const; + void streamRLP(RLPStream& _s, IncludeProof _n) const; private: - mutable h256 m_seedHash; + + mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; @@ -148,7 +148,7 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; + _bi.gasUsed << " " << _bi.timestamp; return _out; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 618703e22..41cd1bba8 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -26,6 +26,7 @@ #include #include "Exceptions.h" #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -112,9 +113,9 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset; string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; - string const c_space = c_border + string(76, ' ') + c_border; + string const c_space = c_border + string(76, ' ') + c_border + EthReset; stringstream ss; ss << c_line << endl; ss << c_space << endl; diff --git a/libethcore/Common.h b/libethcore/Common.h index 296f0d01d..1e0cdc3b1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -189,6 +189,7 @@ struct TransactionSkeleton Address to; u256 value; bytes data; + u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; u256 nonce = UndefinedU256; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9be76926d..6a4a1445f 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -46,6 +46,7 @@ #endif #include "BlockInfo.h" #include "EthashAux.h" +#include "Exceptions.h" using namespace std; using namespace std::chrono; @@ -56,6 +57,26 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); +void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +{ + if (!io_out) + io_out = EthashAux::seedHash((unsigned)_h.number); +} + +void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); + _ex << errinfo_mixHash(_bi.proof.mixHash); + _ex << errinfo_seedHash(_bi.proofCache()); + Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); + _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +} + +void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); +} + std::string Ethash::name() { return "Ethash"; @@ -66,12 +87,23 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) +{ + mixHash = _header[_field].toHash(RLP::VeryStrict); + nonce = _header[++_field].toHash(RLP::VeryStrict); +} + +void Ethash::Solution::streamRLP(RLPStream& io_rlp) const +{ + io_rlp << mixHash << nonce; +} + Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutNonce); - ret.seedHash = _bi.seedHash(); + ret.headerHash = _bi.headerHash(WithoutProof); + ret.seedHash = _bi.proofCache(); return ret; } @@ -84,7 +116,7 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { - EthashAux::full(_header.seedHash(), true, _f); + EthashAux::full(_header.proofCache(), true, _f); } bool Ethash::preVerify(BlockInfo const& _header) @@ -95,9 +127,9 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), + (uint64_t)(u64)_header.proof.nonce, + (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); return ret; @@ -115,7 +147,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -125,9 +157,9 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; + cwarn << "headerHash:" << _header.headerHash(WithoutProof); + cwarn << "nonce:" << _header.proof.nonce; + cwarn << "mixHash:" << _header.proof.mixHash; cwarn << "difficulty:" << _header.difficulty; cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 7ffd887d0..5640152f0 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -28,16 +28,20 @@ #include #include #include "Common.h" -#include "BlockInfo.h" #include "Miner.h" class ethash_cl_miner; namespace dev { + +class RLP; +class RLPStream; + namespace eth { +class BlockInfo; class EthashCLHook; class Ethash @@ -45,8 +49,17 @@ class Ethash public: using Miner = GenericMiner; + using HeaderCache = h256; + static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); + static void composeException(Exception& _ex, BlockInfo& _bi); + static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + struct Solution { + bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } + void populateFromRLP(RLP const& io_rlp, int& io_field); + void streamRLP(RLPStream& io_rlp) const; + static const unsigned Fields = 2; Nonce nonce; h256 mixHash; }; @@ -78,7 +91,6 @@ public: static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } class CPUMiner: public Miner, Worker { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index efb6066f7..db01f3c49 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,6 +200,11 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } +Ethash::Result EthashAux::eval(BlockInfo const& _header) +{ + return eval(_header, _header.proof.nonce); +} + #define DEV_IF_THROWS(X) try { X; } catch (...) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) @@ -252,7 +257,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { - return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); + return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index d5bd60d44..be07f579c 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -78,7 +78,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 764207aef..7b4298047 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -38,7 +38,6 @@ namespace eth * typename Solution * typename CPUMiner * typename GPUMiner - * void assignResult(BlockInfo&, Result) * and a few others. TODO */ using ProofOfWork = Ethash; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 768ed223f..aaafe7ce9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -575,8 +575,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash.abridged() @@ -666,8 +666,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f95a3880e..690fb60ee 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.hash; + bi.proof.mixHash = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.mixHash == work.hash) + if (it->verified.info.proof.mixHash == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.mixHash == work.hash) + if (i.verified.info.proof.mixHash == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..bf55a50ff 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -837,7 +837,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); + m_currentBlock.streamRLP(block, WithProof); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -902,7 +902,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithNonce); + ubi.streamRLP(unclesData, WithProof); ++unclesCount; uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) @@ -970,7 +970,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithNonce); + m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -978,7 +978,7 @@ void State::completeMine() cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.nonce.abridged(), + m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() ); diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..0555b6dcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -169,11 +169,11 @@ public: if (!m_committedToMine) return false; - PoW::assignResult(_result, m_currentBlock); + m_currentBlock.proof = _result; if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..f7c09ebc2 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -99,11 +99,12 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["gasLimit"] = toJS(_bi.gasLimit); res["timestamp"] = toJS(_bi.timestamp); res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); res["logsBloom"] = toJS(_bi.logBloom); - - res["seedHash"] = toJS(_bi.seedHash()); res["target"] = toJS(_bi.boundary()); + + // TODO: move into ProofOfWork. + res["nonce"] = toJS(_bi.proof.nonce); + res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 8373c7c51..ea4686601 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -49,7 +49,6 @@ namespace struct MixPow //dummy POW { typedef int Solution; - static void assignResult(int, BlockInfo const&) {} static bool verify(BlockInfo const&) { return true; } }; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f49ed1e09..b43c4db51 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(BlockInfo& _bi) bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, _bi); + _bi.proof = sol; return completed = true; }); f.setWork(_bi); From 75857ef5d4de3adeeddfc3813ecfc57b267e026f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 13:03:52 -0700 Subject: [PATCH 039/113] Basic Proof-of-Authority sealent. --- eth/main.cpp | 3 + ethminer/MinerAux.h | 28 +++++++-- libdevcrypto/Common.cpp | 5 ++ libdevcrypto/Common.h | 3 + libethcore/Common.cpp | 4 ++ libethcore/Common.h | 13 +++- libethcore/Ethash.cpp | 26 +++++++- libethcore/Ethash.h | 31 +++++++++ libethcore/EthashAux.cpp | 11 ++++ libethcore/EthashAux.h | 1 + libethcore/Farm.h | 1 - libethcore/Miner.h | 11 ---- libethcore/ProofOfWork.cpp | 25 ++++++++ libethcore/ProofOfWork.h | 76 ++++++++++++++++++++++- libethereum/BlockChain.cpp | 4 ++ libethereum/BlockQueue.cpp | 12 ++-- libethereum/Client.cpp | 15 +---- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 +- libethereum/State.h | 2 +- libweb3jsonrpc/JsonHelper.cpp | 2 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 10 ++- 22 files changed, 246 insertions(+), 43 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 67058a473..1e724c7e6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1702,7 +1702,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) { From db577f831fce7fea9997f1fba57a32a882a6d528 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH 040/113] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + 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 BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + 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 BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - 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); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) 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)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); - _ex << errinfo_mixHash(_bi.proof.mixHash); - _ex << errinfo_seedHash(_bi.proofCache()); - Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); - _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); -#else - (void)_ex; - (void)_bi; -#endif -} - -void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) -{ -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); -#else - (void)_ex; - (void)_bi; -#endif -} - -std::string Ethash::name() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) -{ - WorkPackage ret; - ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutProof); -#if ETH_USING_ETHASH - ret.seedHash = _bi.proofCache(); -#endif - return ret; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -void Ethash::prep(BlockInfo const& _header, std::function const& _f) -{ -#if ETH_USING_ETHASH - EthashAux::full(_header.proofCache(), true, _f); -#else - (void)_header; - (void)_f; -#endif + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (number >= ETHASH_EPOCH_LENGTH * 2048) return false; -#if ETH_USING_ETHASH - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ bool Ethash::verify(BlockInfo const& _header) } #endif -#if ETH_USING_ETHASH - auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + 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, unsigned, 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 + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - 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, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#else - using GPUMiner = CPUMiner; -#endif /// Default value of the local work size. Also known as workgroup size. static const unsigned defaultLocalWorkSize; /// Default value of the global work size as a multiplier of the local work size static const unsigned defaultGlobalWorkSizeMultiplier; /// Default value of the milliseconds per global work size (per batch) static const unsigned defaultMSPerBatch; - - struct Farm: public eth::GenericFarm - { - public: - strings sealers() const { return { "cpu", "opencl" }; } - void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } - - void sealBlock(BlockInfo const& _bi) - { - setWork(_bi); - if (m_opencl) - startGPU(); - else - startCPU(); - - setWork(_bi); - ensurePrecomputed((unsigned)_bi.number); - } - - void disable() { stop(); } - - private: - bool m_opencl = false; - }; }; } diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) - return true; - m_miners.clear(); - m_miners.reserve(MinerType::instances()); - for (unsigned i = 0; i < MinerType::instances(); ++i) - { - m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); - -bool BasicAuthority::verify(BlockInfo const& _header) -{ - return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; -} - -bool BasicAuthority::preVerify(BlockInfo const& _header) -{ - return SignatureStruct(_header.proof.sig).isValid(); -} - -BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) -{ - return WorkPackage{_header.headerHash(WithoutProof)}; -} - -void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) -{ - m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); -} - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -class BasicAuthority -{ -public: - struct HeaderCache {}; - static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} - static void composeException(Exception&, BlockInfo&) {} - static void composeExceptionPre(Exception&, BlockInfo&) {} - - struct Solution - { - bool operator==(Solution const& _v) const { return sig == _v.sig; } - void populateFromRLP(RLP const& io_rlp, int& io_field) - { - sig = io_rlp[io_field++].toHash(RLP::VeryStrict); - } - - void streamRLP(RLPStream& io_rlp) const - { - io_rlp << sig; - } - static const unsigned Fields = 1; - Signature sig; - }; - - struct Result - { - Signature sig; - }; - - struct WorkPackage - { - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } - - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - }; - - static const WorkPackage NullWorkPackage; - - static std::string name() { return "BasicAuthority"; } - static unsigned revision() { return 0; } - static void prep(BlockInfo const&, std::function const& = std::function()) {} - static void ensurePrecomputed(unsigned) {} - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - static const Address Authority; - - struct Farm - { - public: - strings sealers() const { return { "default" }; } - void setSealer(std::string const&) {} - void setSecret(Secret const& _s) { m_secret = _s; } - void sealBlock(BlockInfo const& _bi); - void disable() {} - void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } - - private: - Secret m_secret; - std::function m_onSolutionFound; - }; -}; - using ProofOfWork = BasicAuthority; } diff --git a/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + 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 Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + 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 Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady; From bcce3cb72b58ff6c308005b6d83dbf6bf859d1a9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Jul 2015 16:32:04 -0700 Subject: [PATCH 041/113] Tests working for BasicAuthority and Ethash. --- CMakeLists.txt | 32 ++++++++++++++-------------- exp/CMakeLists.txt | 20 ++++++++++++------ exp/main.cpp | 40 ++++++++++++++++++++++++++--------- libdevcore/Common.h | 1 + libethcore/BasicAuthority.cpp | 18 +++++++++++++--- libethcore/BasicAuthority.h | 7 +++++- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 1 + libethcore/EthashAux.cpp | 23 -------------------- libethcore/EthashAux.h | 2 -- libethcore/Sealer.h | 12 +++++++++++ 12 files changed, 97 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 271f3ed65..a75b612c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) - add_subdirectory(libweb3jsonrpc) +# add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) - add_subdirectory(libjsengine) - add_subdirectory(libjsconsole) - add_subdirectory(ethconsole) +# add_subdirectory(libjsengine) +# add_subdirectory(libjsconsole) +# add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -432,33 +432,33 @@ endif () add_subdirectory(libethcore) if (GENERAL) - add_subdirectory(libevm) - add_subdirectory(libethereum) - add_subdirectory(libwebthree) +# add_subdirectory(libevm) +# add_subdirectory(libethereum) +# add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) - add_subdirectory(ethminer) +# add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) - add_subdirectory(ethkey) +# add_subdirectory(ethkey) endif () if (TESTS) - add_subdirectory(libtestutils) - add_subdirectory(test) +# add_subdirectory(libtestutils) +# add_subdirectory(test) if (JSONRPC) - add_subdirectory(ethrpctest) +# add_subdirectory(ethrpctest) endif () endif () if (TOOLS) - add_subdirectory(rlp) - add_subdirectory(abi) - add_subdirectory(ethvm) - add_subdirectory(eth) +# add_subdirectory(rlp) +# add_subdirectory(abi) +# add_subdirectory(ethvm) +# add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index e6360317f..fc8611ad7 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -21,15 +21,21 @@ if (READLINE_FOUND) endif() if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) +# target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} p2p) +#target_link_libraries(${EXECUTABLE} webthree) +#target_link_libraries(${EXECUTABLE} ethereum) +#target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} ethash) - target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} ethash-cl) +# target_link_libraries(${EXECUTABLE} ethash) +# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) endif() +target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) + + + + + diff --git a/exp/main.cpp b/exp/main.cpp index 07eee6a11..fa8603459 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,6 +70,7 @@ namespace fs = boost::filesystem; #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -80,24 +81,43 @@ using namespace eth; int main() { BlockInfo bi; + bi.difficulty = c_genesisDifficulty; + bi.gasLimit = c_genesisGasLimit; + bi.number = 1; + bi.parentHash = sha3("parentHash"); + bytes sealedData; - SealEngineFace* se = BasicAuthority::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); - se->generateSeal(bi); { + KeyPair kp(sha3("test")); + SealEngineFace* se = BasicAuthority::createSealEngine(); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); + cdebug << se->sealers(); + bool done = false; + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.sig(); } - SealEngineFace* se = Ethash::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); - se->generateSeal(bi); - while (!done) - this_thread::sleep_for(chrono::milliseconds(50)); { + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + bool done = false; + se->setSealer("cpu"); + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.nonce(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 303512e57..612b7c685 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using byte = uint8_t; #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) namespace dev { diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index bbf4e3f2a..7006107e1 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); +AddressHash BasicAuthority::s_authorities; bool BasicAuthority::BlockHeaderRaw::verify() const { - return toAddress(recover(m_sig, hashWithout())) == Authority; + return s_authorities.count(toAddress(recover(m_sig, hashWithout()))); } bool BasicAuthority::BlockHeaderRaw::preVerify() const @@ -94,11 +94,23 @@ public: MiningProgress miningProgress() const { return MiningProgress(); } private: + virtual bool onOptionChanging(std::string const& _name, bytes const& _value) + { + RLP rlp(_value); + if (_name == "authorities") + BasicAuthority::s_authorities = rlp.toUnorderedSet
(); + else if (_name == "authority") + m_secret = rlp.toHash(); + else + return false; + return true; + } + Secret m_secret; std::function m_onSealGenerated; }; -SealEngineFace* createSealEngine() +SealEngineFace* BasicAuthority::createSealEngine() { return new BasicAuthoritySealEngine; } diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 616c18340..9127c1d53 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -30,6 +30,7 @@ #include "Sealer.h" class BasicAuthoritySeal; +class BasicAuthoritySealEngine; namespace dev { @@ -48,6 +49,8 @@ namespace eth */ class BasicAuthority { + friend class ::BasicAuthoritySealEngine; + public: // TODO: remove struct Result {}; @@ -70,6 +73,7 @@ public: Signature sig() const { return m_sig; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 1; @@ -84,7 +88,8 @@ public: }; using BlockHeader = BlockHeaderPolished; - static const Address Authority; +private: + static AddressHash s_authorities; }; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index cd55bc1f6..710279cb2 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -158,7 +158,7 @@ public: explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c3f19e723..d385163be 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -119,7 +119,7 @@ bool Ethash::BlockHeaderRaw::verify() const } #endif - auto result = EthashAux::eval(*this); + auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce); bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); @@ -281,6 +281,7 @@ public: { m_farm.onSolutionFound([=](Ethash::Solution const& sol) { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; EthashSeal s(sol.mixHash, sol.nonce); _f(&s); return true; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index eee0e3881..99baa8a05 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -94,6 +94,7 @@ public: h256 const& mixHash() const { return m_mixHash; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 2; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 42a3cf6fb..00537c21a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,18 +200,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } -Ethash::Result EthashAux::eval(BlockInfo const& _header) -{ -#if ETH_USING_ETHASH - return eval(_header, _header.proof.nonce); -#else - (void)_header; - return Ethash::Result(); -#endif -} - -#define DEV_IF_THROWS(X) try { X; } catch (...) - unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); @@ -260,17 +248,6 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) -{ -#if ETH_USING_ETHASH - return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); -#else - (void)_header; - (void)_nonce; - return Ethash::Result(); -#endif -} - Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 5ae24898d..132b9b436 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -79,8 +79,6 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header); - static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index f491240f3..28381444e 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include "Common.h" namespace dev @@ -43,6 +44,9 @@ public: class SealEngineFace { public: + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; @@ -52,6 +56,14 @@ public: // TODO: rename & generalise virtual bool isMining() const { return false; } virtual MiningProgress miningProgress() const { return MiningProgress(); } + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; }; } From d16c51a56f922effd5a70afb6c4bd90a10966937 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jul 2015 23:24:10 +0200 Subject: [PATCH 042/113] Basic test working with same code for Ethash and BasicAuthority. --- CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 1 - ethminer/MinerAux.h | 17 +-- exp/CMakeLists.txt | 6 +- exp/main.cpp | 86 +++++++------ libdevcore/Guards.h | 29 +++++ libdevcore/RLP.h | 3 + libdevcore/TrieDB.h | 9 +- libethcore/BasicAuthority.cpp | 43 ++++--- libethcore/BasicAuthority.h | 16 +-- libethcore/BlockInfo.cpp | 34 +---- libethcore/BlockInfo.h | 64 ++++++--- libethcore/Common.cpp | 3 +- libethcore/Common.h | 14 +- libethcore/Ethash.cpp | 163 ++++++++++++----------- libethcore/Ethash.h | 52 ++------ libethcore/EthashAux.cpp | 17 ++- libethcore/EthashAux.h | 47 ++++++- libethcore/Farm.h | 6 +- libethcore/Miner.h | 4 +- libethcore/ProofOfWork.cpp | 27 ---- libethcore/ProofOfWork.h | 40 ------ libethcore/Sealer.h | 31 +++-- libethereum/BlockChain.cpp | 136 ++++++++++---------- libethereum/BlockChain.h | 113 ++++++++++++++-- libethereum/BlockChainSync.cpp | 11 +- libethereum/BlockQueue.cpp | 24 ++-- libethereum/BlockQueue.h | 8 +- libethereum/CanonBlockChain.cpp | 75 ++++++----- libethereum/CanonBlockChain.h | 45 ++++++- libethereum/Client.cpp | 200 ++++++++++++++++------------- libethereum/Client.h | 119 +++++++++++------ libethereum/ClientBase.cpp | 2 +- libethereum/ClientBase.h | 4 +- libethereum/Interface.h | 8 +- libethereum/State.cpp | 87 ++++++------- libethereum/State.h | 66 ++++------ libethereum/Utility.cpp | 4 +- libethereum/Utility.h | 3 +- libweb3jsonrpc/JsonHelper.cpp | 6 +- libweb3jsonrpc/JsonHelper.h | 14 ++ test/libethcore/dagger.cpp | 3 +- test/libethereum/stateOriginal.cpp | 3 +- 44 files changed, 933 insertions(+), 716 deletions(-) delete mode 100644 libethcore/ProofOfWork.cpp delete mode 100644 libethcore/ProofOfWork.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a75b612c5..421dd1bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,8 +432,8 @@ endif () add_subdirectory(libethcore) if (GENERAL) -# add_subdirectory(libevm) -# add_subdirectory(libethereum) + add_subdirectory(libevm) + add_subdirectory(libethereum) # add_subdirectory(libwebthree) endif () diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4655240e3..2ee8928f5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -208,7 +208,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); diff --git a/eth/main.cpp b/eth/main.cpp index 1e724c7e6..8bbec9f00 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 051128669..61fde605d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #if ETH_ETHASHCL || !ETH_TRUE @@ -387,7 +386,6 @@ public: #endif } -#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -412,10 +410,10 @@ private: genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - GenericFarm f; - f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + GenericFarm f; + f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); - string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; @@ -488,20 +486,20 @@ private: jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; + GenericFarm f; if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) f.startGPU(); - ProofOfWork::WorkPackage current; + EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; while (true) try { bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) + EthashProofOfWork::Solution solution; + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { solution = sol; return completed = true; @@ -595,5 +593,4 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; -#endif }; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index fc8611ad7..b9f477385 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -25,12 +25,12 @@ if (JSONRPC) endif() #target_link_libraries(${EXECUTABLE} webthree) -#target_link_libraries(${EXECUTABLE} ethereum) -#target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) # target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash) -# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} OpenCL) endif() target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/exp/main.cpp b/exp/main.cpp index fa8603459..4a35068f1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -71,13 +70,16 @@ namespace fs = boost::filesystem; #include #include #include +#include +#include +#include +#include using namespace std; using namespace dev; using namespace eth; #endif -#if 1 - +#if 0 int main() { BlockInfo bi; @@ -124,9 +126,7 @@ int main() return 0; } - #elif 0 - int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); @@ -135,10 +135,7 @@ int main() cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); return 0; } - - #elif 0 - int main() { cdebug << "EXP"; @@ -162,9 +159,7 @@ int main() ret = orderedTrieRoot(data); cdebug << ret; } - #elif 0 - int main() { KeyManager keyman; @@ -186,7 +181,6 @@ int main() cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); } - #elif 0 int main() { @@ -246,15 +240,15 @@ int main() #elif 0 int main() { - GenericFarm f; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { BlockInfo bi = g; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { bi.proof = sol; return completed = true; @@ -289,23 +283,16 @@ int main() return 0; } -#elif 0 - -void mine(State& s, BlockChain const& _bc) +#elif 1 +void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) { s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - return completed = s.completeMine(sol); - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + _se->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); } -#elif 0 int main() { cnote << "Testing State..."; @@ -316,47 +303,62 @@ int main() Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; - cout << bc; + using Sealer = Ethash; + CanonBlockChain bc; + auto gbb = bc.headerData(bc.genesisHash()); + assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData)); + + SealEngineFace* se = Sealer::createSealEngine(); + KeyPair kp(sha3("test")); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); - cout << s; + OverlayDB stateDB = State::openDB(bc.genesisHash()); + cnote << bc; + + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); + cnote << s; // Sync up - this won't do much until we use the last state. s.sync(bc); - cout << s; + cnote << s; // Mine to get some ether! - mine(s, bc); + mine(s, bc, se); - bc.attemptImport(s.blockData(), stateDB); + bytes minedBlock = s.blockData(); + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + bc.import(minedBlock, stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; + cnote << "Miner now has" << s.balance(myMiner.address()); + s.resetCurrent(); + cnote << "Miner now has" << s.balance(myMiner.address()); // Inject a transaction to transfer funds from miner to me. Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); - cout << s; + cnote << s; // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - mine(s, bc); + mine(s, bc, se); bc.attemptImport(s.blockData(), stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; return 0; } diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 44d5969e4..135209d23 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex; using SharedMutex = boost::shared_mutex; using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; using RecursiveGuard = std::lock_guard; using ReadGuard = boost::shared_lock; using UpgradableGuard = boost::upgrade_lock; @@ -74,6 +76,33 @@ private: }; using SpinGuard = std::lock_guard; +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a94c8ba55..701f4b8e8 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -393,6 +393,9 @@ public: /// Read the byte stream. bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + /// Swap the contents of the output stream out for some other byte array. void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..05affa677 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -231,8 +231,11 @@ public: } } -protected: - DB* db() const { return m_db; } + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -383,6 +386,7 @@ public: using Super::isEmpty; using Super::root; + using Super::db; using Super::leftOvers; using Super::check; @@ -435,6 +439,7 @@ public: using Super::check; using Super::open; using Super::setRoot; + using Super::db; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7006107e1..22da67080 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -19,6 +19,7 @@ * @date 2014 */ +#include #include "Exceptions.h" #include "BasicAuthority.h" #include "BlockInfo.h" @@ -60,38 +61,38 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri } } +void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} +void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} -class BasicAuthoritySeal: public SealFace +StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const { -public: - BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + return { { "sig", toJS(m_sig) } }; +} - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - BasicAuthority::BlockHeader h(_bi); - h.m_sig = m_sig; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } -private: - Signature m_sig; -}; -class BasicAuthoritySealEngine: public SealEngineFace +class BasicAuthoritySealEngine: public SealEngineBase { public: void setSecret(Secret const& _s) { m_secret = _s; } void generateSeal(BlockInfo const& _bi) { - BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); - m_onSealGenerated(&s); + BasicAuthority::BlockHeader h(_bi); + h.m_sig = sign(m_secret, _bi.hashWithout()); + RLPStream ret; + h.streamRLP(ret); + m_onSealGenerated(ret.out()); } - void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isWorking() const { return false; } + WorkingProgress workingProgress() const { return WorkingProgress(); } private: virtual bool onOptionChanging(std::string const& _name, bytes const& _value) @@ -107,7 +108,7 @@ private: } Secret m_secret; - std::function m_onSealGenerated; + std::function m_onSealGenerated; }; SealEngineFace* BasicAuthority::createSealEngine() diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 9127c1d53..8db47938b 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -52,33 +52,31 @@ class BasicAuthority friend class ::BasicAuthoritySealEngine; public: - // TODO: remove - struct Result {}; - struct WorkPackage {}; - static const WorkPackage NullWorkPackage; - static std::string name() { return "BasicAuthority"; } static unsigned revision() { return 0; } static SealEngineFace* createSealEngine(); class BlockHeaderRaw: public BlockInfo { - friend class ::BasicAuthoritySeal; + friend class ::BasicAuthoritySealEngine; public: + static const unsigned SealFields = 1; + bool verify() const; bool preVerify() const; - WorkPackage package() const { return NullWorkPackage; } Signature sig() const { return m_sig; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 1; - void populateFromHeader(RLP const& _header, Strictness _s); + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); void streamRLPFields(RLPStream& _s) const { _s << m_sig; } void clear() { m_sig = Signature(); } void noteDirty() const {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb07162fb..64961bc40 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,10 +36,10 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt) { - RLP header = extractHeader(_block); - m_hash = sha3(header.data()); + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); populateFromHeader(header, _s); } @@ -58,7 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - m_hashWithout = h256(); + noteDirty(); } h256 const& BlockInfo::boundary() const @@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing) - { - if (gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); - - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); - - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); - - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); - } + if (_s != CheckNothing && gasUsed > gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) gasLimit = selectGasLimit(_parent); gasUsed = 0; difficulty = calculateDifficulty(_parent); + parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const @@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const void BlockInfo::verifyParent(BlockInfo const& _parent) const { - // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); - - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); - // Check timestamp is after previous timestamp. if (parentHash) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 710279cb2..b00fa73fb 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -42,10 +42,18 @@ enum Strictness { CheckEverything, QuickNonce, - IgnoreNonce, + IgnoreSeal, CheckNothing }; +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); + /** @brief Encapsulation of a block header. * Class to contain all of a block header's data. It is able to parse a block header and populate * from some given RLP block serialisation with the static fromHeader(), through the method @@ -69,7 +77,10 @@ enum Strictness */ struct BlockInfo { + friend class BlockChain; public: + static const unsigned BasicFields = 13; + // TODO: make them all private! h256 parentHash; h256 sha3Uncles; @@ -78,7 +89,7 @@ public: h256 transactionsRoot; h256 receiptsRoot; LogBloom logBloom; - u256 difficulty; + u256 difficulty; // TODO: pull out into BlockHeader u256 number; u256 gasLimit; u256 gasUsed; @@ -86,10 +97,12 @@ public: bytes extraData; BlockInfo(); - BlockInfo(bytesConstRef _block, Strictness _s); + explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); + explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -121,17 +134,14 @@ public: /// sha3 of the header only. h256 const& hashWithout() const; - h256 const& hash() const { return m_hash; } - -protected: - static RLP extractHeader(bytesConstRef _block); - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); - void streamRLPFields(RLPStream& _s) const; + h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } void clear(); void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } - static const unsigned BasicFields = 13; +protected: + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal); + void streamRLPFields(RLPStream& _s) const; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. @@ -152,35 +162,50 @@ template class BlockHeaderPolished: public BlockInfoSub { public: + static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields; + BlockHeaderPolished() {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} - explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } - explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); } + explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); } - static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } + // deprecated - just use constructor instead. + static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } + static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } - void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + // deprecated for public API - use constructor. + // TODO: make private. + void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData) + { + populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h); + } void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); BlockInfo::parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); + BlockInfoSub::populateFromParent(_parent); } + // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); + BlockInfoSub::verifyParent(_parent); } - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + // deprecated for public API - use constructor. + // TODO: make private. + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { BlockInfo::m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); + else + BlockInfo::m_hash = dev::sha3(_header.data()); if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); @@ -213,6 +238,13 @@ public: if (_i == WithProof) BlockInfoSub::streamRLPFields(_s); } + + bytes sealFieldsRLP() const + { + RLPStream s; + BlockInfoSub::streamRLPFields(s); + return s.out(); + } }; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 58e506b37..499854584 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -29,7 +29,6 @@ #include #include #include "Exceptions.h" -#include "ProofOfWork.h" #include "BlockInfo.h" using namespace std; using namespace dev; @@ -57,7 +56,7 @@ Network const c_network = Network::Frontier; Network const c_network = Network::Olympic; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 1a688fbd8..5c0a0cc79 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -124,10 +124,16 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, ///< Validate nonce + ValidSeal = 1, ///< Validate seal DontHave = 2, ///< Avoid old blocks - CheckUncles = 4, ///< Check uncle nonces - Default = ValidNonce | DontHave | CheckUncles + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures + Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + None = 0 }; }; @@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(& /** * @brief Describes the progress of a mining operation. */ -struct MiningProgress +struct WorkingProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index d385163be..128822b80 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "Exceptions.h" #include "Farm.h" #include "Miner.h" +#include "Params.h" using namespace std; using namespace std::chrono; @@ -57,8 +59,6 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); - h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) @@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); ex << errinfo_mixHash(m_mixHash); ex << errinfo_seedHash(seedHash()); - Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); ex << errinfo_difficulty(difficulty); @@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } + + if (_s != CheckNothing) + { + if (difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + + if (gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + + if (number && extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + } +} + +void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + + if (gasLimit < c_minGasLimit || + gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || + gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); +} + +void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; } bool Ethash::BlockHeaderRaw::preVerify() const @@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const return slow; } -Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const -{ - WorkPackage ret; - ret.boundary = boundary(); - ret.headerHash = hashWithout(); - ret.seedHash = seedHash(); - return ret; -} - void Ethash::BlockHeaderRaw::prep(std::function const& _f) const { EthashAux::full(seedHash(), true, _f); } +StringHashMap Ethash::BlockHeaderRaw::jsInfo() const +{ + return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; +} @@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function const& _f) const -class EthashCPUMiner: public GenericMiner, Worker +class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -190,7 +214,7 @@ private: }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker +class EthashGPUMiner: public GenericMiner, Worker { friend class dev::eth::EthashCLHook; @@ -234,66 +258,84 @@ private: }; #endif -class EthashSeal: public SealFace +struct EthashSealEngine: public SealEngineBase { -public: - EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} - - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - Ethash::BlockHeader h(_bi); - h.m_mixHash = m_mixHash; - h.m_nonce = m_nonce; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } - -private: - h256 m_mixHash; - h64 m_nonce; -}; + friend class Ethash; -struct EthashSealEngine: public SealEngineFace -{ public: EthashSealEngine() { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; #if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; #endif m_farm.setSealers(sealers); } - strings sealers() const override { return { "cpu", "opencl" }; } + strings sealers() const override + { + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; + } void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void disable() override { m_farm.stop(); } + void cancelGeneration() override { m_farm.stop(); } void generateSeal(BlockInfo const& _bi) override { - m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); m_farm.start(m_sealer); - m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + m_farm.setWork(m_sealing); // TODO: take out one before or one after... Ethash::ensurePrecomputed((unsigned)_bi.number); } - void onSealGenerated(std::function const& _f) override + void onSealGenerated(std::function const& _f) override { - m_farm.onSolutionFound([=](Ethash::Solution const& sol) + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) { cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - EthashSeal s(sol.mixHash, sol.nonce); - _f(&s); + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); return true; }); } private: bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; }; +void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + // Go via the farm since the handler function object is stored as a local within the Farm's lambda. + // Has the side effect of stopping local workers, which is good, as long as it only does it for + // valid submissions. + static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); +} + +bool Ethash::isWorking(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.isMining(); + return false; +} + +WorkingProgress Ethash::workingProgress(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.miningProgress(); + return WorkingProgress(); +} + SealEngineFace* Ethash::createSealEngine() { return new EthashSealEngine; @@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE -using UniqueGuard = std::unique_lock; - -template -class Notified -{ -public: - Notified() {} - Notified(N const& _v): m_value(_v) {} - Notified(Notified const&) = delete; - Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - - operator N() const { UniqueGuard l(m_mutex); return m_value; } - - void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } - -private: - mutable Mutex m_mutex; - mutable std::condition_variable m_cv; - N m_value; -}; - class EthashCLHook: public ethash_cl_miner::search_hook { public: diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99baa8a05..576621bd4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -53,59 +53,42 @@ public: static unsigned revision(); static SealEngineFace* createSealEngine(); - // TODO: remove or virtualize - struct Solution - { - h64 nonce; - h256 mixHash; - }; - // TODO: make private - struct Result - { - h256 value; - h256 mixHash; - }; - // TODO: virtualise - struct WorkPackage - { - WorkPackage() = default; - - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } + using Nonce = h64; - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; - }; - static const WorkPackage NullWorkPackage; + static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce); + static bool isWorking(SealEngineFace* _engine); + static WorkingProgress workingProgress(SealEngineFace* _engine); class BlockHeaderRaw: public BlockInfo { - friend class EthashSeal; + friend class EthashSealEngine; public: + static const unsigned SealFields = 2; + bool verify() const; bool preVerify() const; void prep(std::function const& _f = std::function()) const; - WorkPackage package() const; h256 const& seedHash() const; - h64 const& nonce() const { return m_nonce; } + Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 2; - void populateFromHeader(RLP const& _header, Strictness _s); - void clear() { m_mixHash = h256(); m_nonce = h64(); } + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); + void clear() { m_mixHash = h256(); m_nonce = Nonce(); } void noteDirty() const { m_seedHash = h256(); } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - h64 m_nonce; + Nonce m_nonce; h256 m_mixHash; mutable h256 m_seedHash; @@ -115,13 +98,6 @@ public: // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); - - /// Default value of the local work size. Also known as workgroup size. - static const unsigned defaultLocalWorkSize; - /// Default value of the global work size as a multiplier of the local work size - static const unsigned defaultGlobalWorkSizeMultiplier; - /// Default value of the milliseconds per global work size (per batch) - static const unsigned defaultMSPerBatch; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 00537c21a..c511978db 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; } EthashAux* dev::eth::EthashAux::s_this = nullptr; +const unsigned EthashProofOfWork::defaultLocalWorkSize = 64; +const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE +const unsigned EthashProofOfWork::defaultMSPerBatch = 0; +const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage(); + EthashAux::~EthashAux() { } @@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; } -Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) if (FullType dag = get()->m_fulls[_seedHash].lock()) return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { - return Ethash::Result{ ~h256(), h256() }; + return EthashProofOfWork::Result{ ~h256(), h256() }; } } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 132b9b436..d42e46d91 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -34,6 +34,47 @@ namespace eth struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; +/// Proof of work definition for Ethash. +struct EthashProofOfWork +{ + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + WorkPackage() = default; + WorkPackage(Ethash::BlockHeader const& _bh): + boundary(_bh.boundary()), + headerHash(_bh.hashWithout()), + seedHash(_bh.seedHash()) + {} + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; +}; + class EthashAux { public: @@ -46,7 +87,7 @@ public: LightAllocation(h256 const& _seedHash); ~LightAllocation(); bytesConstRef data() const; - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; ethash_light_t light; uint64_t size; }; @@ -55,7 +96,7 @@ public: { FullAllocation(ethash_light_t _light, ethash_callback_t _cb); ~FullAllocation(); - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; bytesConstRef data() const; uint64_t size() const { return ethash_full_dag_size(full); } ethash_full_t full; @@ -79,7 +120,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: EthashAux() {} diff --git a/libethcore/Farm.h b/libethcore/Farm.h index b69f8325a..c86b4804e 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -123,9 +123,9 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const + WorkingProgress const& miningProgress() const { - MiningProgress p; + WorkingProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); @@ -195,7 +195,7 @@ private: std::atomic m_isMining = {false}; mutable SharedMutex x_progress; - mutable MiningProgress m_progress; + mutable WorkingProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 03eba9880..90a5902c4 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,9 +36,9 @@ namespace dev namespace eth { -struct MineInfo: public MiningProgress {}; +struct MineInfo: public WorkingProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) +inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p) { _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp deleted file mode 100644 index 843db72c7..000000000 --- a/libethcore/ProofOfWork.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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 ProofOfWork.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "ProofOfWork.h" -#include "BlockInfo.h" -using namespace std; -using namespace dev; -using namespace eth; - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h deleted file mode 100644 index f55c54df6..000000000 --- a/libethcore/ProofOfWork.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 ProofOfWork.h - * @author Gav Wood - * @date 2014 - * - * Determines the PoW algorithm. - */ - -#pragma once - -#include -#include -#include "Common.h" -//#include "Ethash.h" -#include "BasicAuthority.h" - -namespace dev -{ -namespace eth -{ - -using ProofOfWork = BasicAuthority; - -} -} diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index 28381444e..137659dfc 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -25,6 +25,7 @@ #include #include +#include #include "Common.h" namespace dev @@ -34,28 +35,22 @@ namespace eth class BlockInfo; -class SealFace -{ -public: - virtual bool wouldSealHeader(BlockInfo const&) const { return true; } - virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; -}; - class SealEngineFace { public: + virtual std::string name() const = 0; + virtual unsigned revision() const = 0; + virtual unsigned sealFields() const = 0; + virtual bytes sealRLP() const = 0; + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; - virtual void onSealGenerated(std::function const& _f) = 0; - virtual void disable() {} - - // TODO: rename & generalise - virtual bool isMining() const { return false; } - virtual MiningProgress miningProgress() const { return MiningProgress(); } + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} protected: virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } @@ -66,5 +61,15 @@ private: std::unordered_map m_options; }; +template +class SealEngineBase: public SealEngineFace +{ +public: + std::string name() const override { return Sealer::name(); } + unsigned revision() const override { return Sealer::revision(); } + unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; } + bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); } +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 14b13b90d..aae8cbd10 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,12 +35,12 @@ #include #include #include -#include #include #include #include #include "GenesisInfo.h" #include "State.h" +#include "Utility.h" #include "Defaults.h" using namespace std; @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 1 +#define ETH_CATCH 0 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 @@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): + m_genesisState(_genesisState) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit // Initialise with the genesis as the last block on the longest chain. m_genesisBlock = _genesisBlock; m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); + m_genesisState = _genesisState; + + // remove the next line real soon. we don't need to be supporting this forever. + upgradeDatabase(_path, genesisHash()); if (open(_path, _we) != c_minorProtocolVersion) rebuild(_path, _p); @@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); - BlockInfo bi(b); + BlockInfo bi(&b); if (_prepPoW) - Ethash::prep(bi); + Ethash::ensurePrecomputed((unsigned)bi.number); if (bi.parentHash != lastHash) { @@ -351,7 +356,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; @@ -388,7 +393,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad, _ir); + block = verifyBlock(&_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) @@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& auto parentBlock = block(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; - clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); + clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); @@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(_block, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this); for (unsigned i = 0; i < s.pending().size(); ++i) { @@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db) try { cout << "block..." << flush; - BlockInfo bi = info(h); - cout << "details..." << flush; - BlockDetails bd = details(h); + BlockInfo bi(block(h)); + cout << "extras..." << flush; + details(h); cout << "state..." << flush; if (_db.exists(bi.stateRoot)) break; @@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +bytes BlockChain::headerData(h256 const& _hash) const { - VerifiedBlockRef res; - try - { - Strictness strictness = Strictness::CheckEverything; - if (~_ir & ImportRequirements::ValidNonce) - strictness = Strictness::IgnoreNonce; + if (_hash == m_genesisHash) + return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes(); - res.info.populate(_block, strictness); - res.info.verifyInternals(&_block); - } - catch (Exception& ex) { - ex << errinfo_phase(1); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; + ReadGuard l(x_blocks); + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + return BlockInfo::extractHeader(&it->second).data().toBytes(); } - RLP r(_block); - unsigned i = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_uncleIndex(i); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; - } - i = 0; - for (RLP const& tr: r[1]) + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + + if (d.empty()) { - bytesConstRef d = tr.data(); - try - { - res.transactions.push_back(Transaction(d, CheckTransaction::Everything)); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_transactionIndex(i); - ex << errinfo_transaction(d.toBytes()); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; + cwarn << "Couldn't find requested block:" << _hash; + return bytes(); } - res.block = bytesConstRef(&_block); - return res; + + noteUsed(_hash); + + WriteGuard l(x_blocks); + m_blocks[_hash].resize(d.size()); + memcpy(m_blocks[_hash].data(), d.data(), d.size()); + + return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes(); } +State BlockChain::genesisState(OverlayDB const& _db) +{ + State ret(_db, BaseState::Empty); + dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? + ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. + ret.m_previousBlock = BlockInfo(&m_genesisBlock); + return ret; +} + + + + + + + + + + + + + + + + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 638c9c3af..50965f2b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,6 +37,7 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" +#include "State.h" namespace std { @@ -86,6 +87,13 @@ enum { }; using ProgressCallback = std::function; +using StateDefinition = std::unordered_map; + +class VersionChecker +{ +public: + VersionChecker(std::string const& _dbPath, h256 const& _genesisHash); +}; /** * @brief Implements the blockchain database. All data this gives is disk-backed. @@ -94,7 +102,7 @@ using ProgressCallback = std::function; class BlockChain { public: - BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); ~BlockChain(); /// Attempt a database re-open. @@ -120,14 +128,17 @@ public: /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; - /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. - BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); } + /// Get the partial-header of a block (or the most recent mined if none given). Thread-safe. + BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); } BlockInfo info() const { return info(currentHash()); } /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. bytes block(h256 const& _hash) const; bytes block() const { return block(currentHash()); } - bytes oldBlock(h256 const& _hash) const; + + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes headerData(h256 const& _hash) const; + bytes headerData() const { return headerData(currentHash()); } /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. BlockDetails details(h256 const& _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } @@ -264,13 +275,16 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); - /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); - /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } -private: + /// Get a pre-made genesis State object. + State genesisState(OverlayDB const& _db); + + /// Verify block and prepare it for enactment + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + +protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); @@ -345,6 +359,7 @@ private: /// Genesis block info. h256 m_genesisHash; bytes m_genesisBlock; + std::unordered_map m_genesisState; ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; @@ -354,6 +369,88 @@ private: friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; +template +class FullBlockChain: public BlockChain +{ +public: + using BlockHeader = typename Sealer::BlockHeader; + + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path, _we, _p) + {} + + /// Get the header of a block (or the most recent mined if none given). Thread-safe. + typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } + typename Sealer::BlockHeader header() const { return header(currentHash()); } + + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + { + VerifiedBlockRef res; + + try + { + BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); + h.verifyInternals(_block); + h.verifyParent(header(h.parentHash)); + res.info = static_cast(h); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + if (_ir && ImportRequirements::UncleBasic) + for (auto const& uncle: r[2]) + { + try + { + BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + if (_ir && ImportRequirements::TransactionBasic) + for (RLP const& tr: r[1]) + { + bytesConstRef d = tr.data(); + try + { + res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None)); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_transactionIndex(i); + ex << errinfo_transaction(d.toBytes()); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + res.block = bytesConstRef(_block); + return res; + } +}; + std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); } diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 6aede0c16..ed022fb75 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const for (unsigned i = 0; i < itemCount; ++i) { - auto h = BlockInfo::headerHash(_r[i].data()); + auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) + switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; @@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const logNewBlock(h); if (m_state == SyncState::NewBlocks) { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); + BlockInfo bi(_r[i].data()); if (bi.number > maxUnknownNumber) { maxUnknownNumber = bi.number; @@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP con { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); + auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { - switch (host().bq().import(_r[0].data(), host().chain())) + switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b6c548c1f..6b400b236 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); } catch (...) { @@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() } } -ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) +ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. - h256 h = BlockInfo::headerHash(_block); + h256 h = BlockInfo::headerHashFromBlock(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; @@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::AlreadyKnown; } - // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { - // TODO: quick verify - bi.populate(_block); - bi.verifyInternals(_block); + // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer + // VERIFY: populates from the block and checks the block is internally coherent. + bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info; } catch (Exception const& _e) { @@ -218,7 +216,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! - if (_bc.isKnown(h)) + if (m_bc->isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; @@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else @@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; @@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad) return !m_readySet.empty(); } -void BlockQueue::tick(BlockChain const& _bc) +void BlockQueue::tick() { vector> todo; { @@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc) cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) - import(&b.second, _bc); + import(&b.second); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index b9e6f5b3b..97fca7c72 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -76,11 +76,13 @@ public: BlockQueue(); ~BlockQueue(); + void setChain(BlockChain const& _bc) { m_bc = &_bc; } + /// Import a block into the queue. - ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. - void tick(BlockChain const& _bc); + void tick(); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. @@ -138,6 +140,8 @@ private: void updateBad_WITH_LOCK(h256 const& _bad); void drainVerified_WITH_BOTH_LOCKS(); + BlockChain const* m_bc; ///< The blockchain into which our imports go. + mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. h256Hash m_readySet; ///< All blocks ready for chain import. diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 4e6d89243..eee4b98b7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -41,14 +40,44 @@ namespace js = json_spirit; #define ETH_CATCH 1 -std::unordered_map const& dev::eth::genesisState() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); +std::string CanonBlockChain::s_genesisStateJSON; + +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) +{ +} + +bytes CanonBlockChain::createGenesisBlock() +{ + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + SecureTrieDB state(&db); + state.init(); + dev::eth::commit(createGenesisState(), state); + stateRoot = state.root(); + } + + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +unordered_map CanonBlockChain::createGenesisState() { static std::unordered_map s_ret; if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(c_genesisInfo, val); + json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()) { u256 balance; @@ -68,53 +97,29 @@ std::unordered_map const& dev::eth::genesisState() return s_ret; } -// TODO: place Registry in here. - -std::unique_ptr CanonBlockChain::s_genesis; -boost::shared_mutex CanonBlockChain::x_genesis; -Nonce CanonBlockChain::s_nonce(u64(42)); - -bytes CanonBlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - SecureTrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - BlockChain(createGenesisBlock(), _path, _we, _pc) +void CanonBlockChain::setGenesisState(std::string const& _json) { + WriteGuard l(x_genesis); + s_genesisStateJSON = _json; + s_genesis.reset(); } -void CanonBlockChain::setGenesisNonce(Nonce const& _n) +void CanonBlockChain::setGenesisNonce(Nonce const& _n) { WriteGuard l(x_genesis); s_nonce = _n; s_genesis.reset(); } -BlockInfo const& CanonBlockChain::genesis() +Ethash::BlockHeader const& CanonBlockChain::genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); - s_genesis.reset(new BlockInfo); - s_genesis->populate(&gb); + s_genesis.reset(new Ethash::BlockHeader); + s_genesis->populate(&gb, CheckEverything); } return *s_genesis; } diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index c16479f0d..d79926703 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BlockDetails.h" #include "Account.h" @@ -45,7 +46,32 @@ std::unordered_map const& genesisState(); * @threadsafe * @todo Make not memory hog (should actually act as a cache and deallocate old entries). */ -class CanonBlockChain: public BlockChain +template +class CanonBlockChain: public FullBlockChain +{ +public: + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + ~CanonBlockChain() {} + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock() + { + RLPStream block(3); + block.appendList(Sealer::BlockHeader::Fields) + << h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string(); + bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP(); + block.appendRaw(sealFields, Sealer::BlockHeader::SealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); + } +}; + +template <> +class CanonBlockChain: public FullBlockChain { public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} @@ -53,22 +79,35 @@ public: ~CanonBlockChain() {} /// @returns the genesis block header. - static BlockInfo const& genesis(); + static Ethash::BlockHeader const& genesis(); /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static std::unordered_map createGenesisState(); + /// Alter the value of the genesis block's nonce. /// @warning Unless you're very careful, make sure you call this right at the start of the /// program, before anything has had the chance to use this class at all. static void setGenesisNonce(Nonce const& _n); + /// Alter all the genesis block's state by giving a JSON string with account details. + /// @TODO implement. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisState(std::string const&); + + // TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, + private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + static std::unique_ptr s_genesis; static Nonce s_nonce; + static std::string s_genesisStateJSON; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 918480263..ec37302a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -72,47 +72,43 @@ static const Addresses c_canaries = Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph }; -VersionChecker::VersionChecker(string const& _dbPath) +Client::Client(std::shared_ptr _gp): + Worker("eth", 0), + m_gp(_gp ? _gp : make_shared()) { - upgradeDatabase(_dbPath); } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Client(_extNet, make_shared(), _dbPath, _forceAction, _networkId) +void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId) { - startWorking(); -} + // Cannot be opened until after blockchain is open, since BlockChain may upgrade the database. + // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database + // until after the construction. + m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); + m_preMine = State(m_stateDB); + m_postMine = State(m_stateDB); + // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. + m_preMine = bc().genesisState(m_stateDB); -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth", 0), - m_vc(_dbPath), - m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), - m_gp(_gp), - m_stateDB(State::openDB(_dbPath, _forceAction)), - m_preMine(m_stateDB, BaseState::CanonGenesis), - m_postMine(m_stateDB) -{ - if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + m_bq.setChain(bc()); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_sealEngine = shared_ptr(Ethash::createSealEngine()); - m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); + bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_gp->update(m_bc); + if (_forceAction == WithExisting::Rescue) + m_bc.rescue(m_stateDB); + + m_gp->update(bc()); - auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); + auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId)); m_host = host; _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common if (_dbPath.size()) Defaults::setDBPath(_dbPath); doWork(); - startWorking(); } @@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000) this_thread::sleep_for(std::chrono::milliseconds(500)); - return m_bq.import(&_block, bc(), _isSafe); + return m_bq.import(&_block, _isSafe); } tuple Client::syncQueue(unsigned _max) { stopWorking(); - return m_bc.sync(m_bq, m_stateDB, _max); + return bc().sync(m_bq, m_stateDB, _max); } void Client::onBadBlock(Exception& _ex) const @@ -294,7 +290,7 @@ void Client::startedWorking() clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -309,7 +305,7 @@ void Client::doneWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -328,7 +324,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.disable(); + m_sealEngine->cancelGeneration(); { WriteGuard l(x_postMine); @@ -340,10 +336,10 @@ void Client::killChain() m_working = State(); m_stateDB = OverlayDB(); - m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); - m_bc.reopen(Defaults::dbPath(), WithExisting::Kill); + m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); + bc().reopen(Defaults::dbPath(), WithExisting::Kill); - m_preMine = State(m_stateDB, BaseState::CanonGenesis); + m_preMine = bc().genesisState(m_stateDB); m_postMine = State(m_stateDB); } @@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); - auto receipts = m_bc.receipts(_block).receipts; + auto d = bc().info(_block); + auto receipts = bc().receipts(_block).receipts; Guard l(x_filtersWatches); io_changed.insert(ChainChangedFilter); @@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable) startMining(); } -MiningProgress Client::miningProgress() const +bool Client::isMining() const { - if (m_farm.isMining()) - return m_farm.miningProgress(); - return MiningProgress(); + return Ethash::isWorking(m_sealEngine.get()); +} + +WorkingProgress Client::miningProgress() const +{ + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()); + return WorkingProgress(); } uint64_t Client::hashrate() const { - if (m_farm.isMining()) - return m_farm.miningProgress().rate(); + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()).rate(); return 0; } @@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -ProofOfWork::WorkPackage Client::getWork() -{ - // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. - // this will be reset as soon as a new block arrives, allowing more transactions to be processed. - bool oldShould = shouldServeWork(); - m_lastGetWork = chrono::system_clock::now(); - - if (!m_mineOnBadChain && isChainBad()) - return ProofOfWork::WorkPackage(); - - // if this request has made us bother to serve work, prep it now. - if (!oldShould && shouldServeWork()) - onPostStateChanged(); - else - // otherwise, set this to true so that it gets prepped next time. - m_remoteWorking = true; - return ProofOfWork::package(m_miningInfo); -} - -bool Client::submitWork(ProofOfWork::Solution const& _solution) -{ - bytes newBlock; - DEV_WRITE_GUARDED(x_working) - if (!m_working.completeMine(_solution)) - return false; - - DEV_READ_GUARDED(x_working) - { - DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; - newBlock = m_working.blockData(); - } - - // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. - m_bq.import(&newBlock, m_bc, true); - - return true; -} - unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; @@ -553,7 +515,7 @@ void Client::syncBlockQueue() ImportRoute ir; unsigned count; Timer t; - tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); if (count) @@ -577,7 +539,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; DEV_WRITE_GUARDED(x_working) - tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp); if (newPendingReceipts.empty()) return; @@ -590,7 +552,7 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restart mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& h: _ir.deadBlocks) { clog(ClientTrace) << "Dead block:" << h; - for (auto const& t: m_bc.transactions(h)) + for (auto const& t: bc().transactions(h)) { clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, IfDropped::Retry); @@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir) newPreMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + preChanged = newPreMine.sync(bc()); if (preChanged || m_postMine.address() != m_preMine.address()) { @@ -700,7 +662,7 @@ void Client::rejigMining() { clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) - m_working.commitToMine(m_bc, m_extraData); + m_working.commitToMine(bc(), m_extraData); DEV_READ_GUARDED(x_working) { DEV_WRITE_GUARDED(x_postMine) @@ -709,10 +671,10 @@ void Client::rejigMining() } if (m_wouldMine) - m_farm.sealBlock(m_miningInfo); + m_sealEngine->generateSeal(m_miningInfo); } if (!m_wouldMine) - m_farm.disable(); + m_sealEngine->cancelGeneration(); } void Client::noteChanged(h256Hash const& _filters) @@ -768,7 +730,7 @@ void Client::tick() { m_report.ticks++; checkWatchGarbage(); - m_bq.tick(m_bc); + m_bq.tick(); m_lastTick = chrono::system_clock::now(); if (m_report.ticks == 15) clog(ClientTrace) << activityReport(); @@ -792,7 +754,7 @@ void Client::checkWatchGarbage() uninstallWatch(i); // blockchain GC - m_bc.garbageCollect(); + bc().garbageCollect(); m_lastGarbageCollection = chrono::system_clock::now(); } @@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const try { State ret(m_stateDB); - ret.populateFromChain(m_bc, _block); + ret.populateFromChain(bc(), _block); return ret.fromPending(_txi); } catch (Exception& ex) @@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const try { State ret(m_stateDB); - PopulationStatistics s = ret.populateFromChain(m_bc, _block); + PopulationStatistics s = ret.populateFromChain(bc(), _block); if (o_stats) swap(s, *o_stats); return ret; @@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const auto h = m_host.lock(); return h ? h->status() : SyncStatus(); } + +bool Client::submitSealed(bytes const& _header) +{ + DEV_WRITE_GUARDED(x_working) + if (!m_working.sealBlock(_header)) + return false; + + bytes newBlock; + DEV_READ_GUARDED(x_working) + { + DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + newBlock = m_working.blockData(); + } + + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. + return m_bq.import(&newBlock, true) == ImportResult::Success; +} + + + + + + + + + + + + + + +std::tuple EthashClient::getEthashWork() +{ + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); + m_lastGetWork = chrono::system_clock::now(); + + if (!m_mineOnBadChain && isChainBad()) + return std::tuple(); + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; + Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + return std::tuple(bh.boundary(), bh.hashWithout(), bh.seedHash()); +} + +bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce) +{ + Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce); + return true; +} + diff --git a/libethereum/Client.h b/libethereum/Client.h index 9ae7c7e09..73609bd71 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -60,12 +60,6 @@ enum ClientWorkState Deleted }; -class VersionChecker -{ -public: - VersionChecker(std::string const& _dbPath); -}; - struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; @@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); /** * @brief Main API hub for interfacing with Ethereum. + * Not to be used directly - subclass. */ class Client: public ClientBase, Worker { public: /// New-style Constructor. - explicit Client( - p2p::Host* _host, - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); - - explicit Client( - p2p::Host* _host, - std::shared_ptr _gpForAdoption, // pass it in with new. - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); + /// Any final derived class's constructor should make sure they call init(). + explicit Client(std::shared_ptr _gpForAdoption); /// Destructor. virtual ~Client(); @@ -129,7 +112,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. - CanonBlockChain const& blockChain() const { return m_bc; } + BlockChain const& blockChain() const { return bc(); } /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. @@ -176,26 +159,16 @@ public: /// NOT thread-safe void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? - bool isMining() const override { return m_farm.isMining(); } + bool isMining() const override; /// Are we mining now? bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MiningProgress miningProgress() const override; + WorkingProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); - /// Update to the latest transactions and get hash of the current block to be mined minus the - /// nonce (the 'work hash') and the difficulty to be met. - virtual ProofOfWork::WorkPackage getWork() override; - - /** @brief Submit the proof for the proof-of-work. - * @param _s A valid solution. - * @return true if the solution was indeed valid and accepted. - */ - virtual bool submitWork(ProofOfWork::Solution const& _proof) override; - // Debug stuff: DownloadMan const* downloadMan() const; @@ -218,12 +191,20 @@ public: /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } /// Rewind to a prior head. - void rewind(unsigned _n) { m_bc.rewind(_n); } + void rewind(unsigned _n) { bc().rewind(_n); } + /// Rescue the chain. + void rescue() { bc().rescue(m_stateDB); } + /// Get the seal engine. + SealEngineFace* sealEngine() const { return m_sealEngine.get(); } protected: + /// Perform critical setup functions. + /// Must be called in the constructor of the finally derived class. + void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); + /// InterfaceStub methods - virtual BlockChain& bc() override { return m_bc; } - virtual BlockChain const& bc() const override { return m_bc; } + virtual BlockChain& bc() override = 0; + virtual BlockChain const& bc() const override = 0; /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. @@ -245,7 +226,10 @@ protected: /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. void noteChanged(h256Hash const& _filters); -private: + /// Submit + bool submitSealed(bytes const& _s); + +protected: /// Called when Worker is starting. void startedWorking() override; @@ -291,8 +275,6 @@ private: /// @warning May be called from any thread. void onBadBlock(Exception& _ex) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -339,5 +321,64 @@ private: bytes m_extraData; }; +template +class SpecialisedClient: public Client +{ +public: + explicit SpecialisedClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): + Client(_gpForAdoption), + m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }) + { + m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSealGenerated([=](bytes const& header){ + return this->submitSealed(header); + }); + init(_host, _dbPath, _forceAction, _networkId); + } + + /// Get the object representing the current canonical blockchain. + CanonBlockChain const& blockChain() const { return m_bc; } + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } + +protected: + CanonBlockChain m_bc; ///< Maintains block database. +}; + +class EthashClient: public SpecialisedClient +{ +public: + /// Trivial forwarding constructor. + explicit EthashClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + + /// Update to the latest transactions and get hash of the current block to be mined minus the + /// nonce (the 'work hash') and the difficulty to be met. + virtual std::tuple getEthashWork() override; + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ + virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } +}; + } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f463b0195..769880269 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const auto bl = bc().block(_blockHash); RLP b(bl); if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); + return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData); else return BlockInfo(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 82f03def0..874f10548 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -156,9 +156,7 @@ public: virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } - virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } - virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } - virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } + virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 973433af9..213e7fb26 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" @@ -207,12 +207,12 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual ProofOfWork::WorkPackage getWork() = 0; + virtual std::tuple getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); } /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; + virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); } /// Check the progress of the mining. - virtual MiningProgress miningProgress() const = 0; + virtual WorkingProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1656109a9..ee2078a07 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } -OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) +OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; @@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) boost::filesystem::remove_all(path + "/state"); } - path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); + path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); ldb::Options o; @@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("beginning of Genesis construction.", true); - if (_bs == BaseState::CanonGenesis) - { - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); - - paranoia("after DB commit of Genesis construction.", true); - m_previousBlock = CanonBlockChain::genesis(); - } - else - m_previousBlock.clear(); - - resetCurrent(); - - assert(m_state.root() == m_previousBlock.stateRoot); + m_previousBlock.clear(); + m_currentBlock.clear(); +// assert(m_state.root() == m_previousBlock.stateRoot); paranoia("end of normal construction.", true); } @@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip; - bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip, _ir); + BlockInfo bip(_bc.block(bi.parentHash)); + sync(_bc, bi.parentHash, bip); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; - auto vb = BlockChain::verifyBlock(b); + auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); t.restart(); - enact(vb, _bc, _ir); + enact(vb, _bc); ret.enact = t.elapsed(); } else @@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi, _ir); + sync(_bc, _h, bi); } return ret; @@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ void State::commit() { - m_touched += dev::eth::commit(m_cache, m_db, m_state); + m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } @@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) +bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi) { - (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -355,7 +342,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor { cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; - cwarn << "Bailing."; + cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); } m_previousBlock = bi; @@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) { #if ETH_TIMED_ENACTMENTS Timer t; @@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _ir); + auto ret = enact(_block, _bc); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire RLP rlp(_block); cleanup(false); - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal); m_currentBlock = bi; m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); @@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) { DEV_TIMED_FUNCTION_ABOVE(500); @@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = _block.info; m_currentBlock.noteDirty(); + m_currentBlock = _block.info; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } @@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + // IgnoreSeal since it's a VerifiedBlock. + BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; if (!_bc.isKnown(uncle.parentHash)) @@ -829,6 +817,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { + (void)_bc; + /* commitToMine(_bc); // Update difficulty according to timestamp. @@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out(), std::function(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) { cwarn << "Bad block: " << _e.what(); } - +*/ return false; } @@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) for (auto const& u: us) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { - BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithProof); + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); ++unclesCount; - uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) break; } @@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) m_committedToMine = true; } -void State::completeMine() +bool State::sealBlock(bytesConstRef _header) { - cdebug << "Completing mine!"; + if (!m_committedToMine) + return false; + + cdebug << "Sealing block!"; // Got it! // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithProof); + ret.appendRaw(_header); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); - m_currentBlock.noteDirty(); + m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; -/* StructuredLogger::minedNewBlock( + // TODO: move into Sealer + StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.proof.nonce.abridged(), + "", // Can't give the nonce here. "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - );*/ + ); // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. @@ -989,6 +982,8 @@ void State::completeMine() m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; + + return true; } bool State::addressInUse(Address _id) const diff --git a/libethereum/State.h b/libethereum/State.h index f6a8471ea..805215ee5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "Account.h" @@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati enum class BaseState { PreExisting, - Empty, - CanonGenesis + Empty }; enum class Permanence @@ -104,6 +102,7 @@ class State friend class dev::test::ImportTest; friend class dev::test::StateLoader; friend class Executive; + friend class BlockChain; public: /// Default constructor; creates with a blank database prepopulated with the genesis block. @@ -125,7 +124,7 @@ public: ~State(); /// Construct state object from arbitrary point in blockchain. - PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None); /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. @@ -133,8 +132,8 @@ public: Address address() const { return m_ourAddress; } /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. - static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust); - static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } + static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); } OverlayDB const& db() const { return m_db; } OverlayDB& db() { return m_db; } @@ -163,22 +162,20 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. - template - bool completeMine(typename PoW::Solution const& _result) - { - if (!m_committedToMine) - return false; - - m_currentBlock.proof = _result; - if (!PoW::verify(m_currentBlock)) - return false; - -// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - - completeMine(); - - return true; - } + /// TODO: verify it prior to calling this. + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * while (notYetMined) + * { + * // lock + * commitToMine(_blockChain); // will call uncommitToMine if a repeat. + * completeMine(); + * // unlock + * @endcode + */ + bool sealBlock(bytes const& _header) { return sealBlock(&_header); } + bool sealBlock(bytesConstRef _header); /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. @@ -295,11 +292,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); + bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -313,19 +310,6 @@ public: void resetCurrent(); private: - /** Commit to DB and build the final block if the previous call to mine()'s result is completion. - * Typically looks like: - * @code - * while (notYetMined) - * { - * // lock - * commitToMine(_blockChain); // will call uncommitToMine if a repeat. - * completeMine(); - * // unlock - * @endcode - */ - void completeMine(); - /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -340,7 +324,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -386,7 +370,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, SecureTrieDB& _state) { AddressHash ret; for (auto const& i: _cache) @@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, } else { - SecureTrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); @@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, if (i.second.isFreshCode()) { h256 ch = sha3(i.second.code()); - _db.insert(ch, &i.second.code()); + _state.db()->insert(ch, &i.second.code()); s << ch; } else diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index e02012cd5..1b97f82e7 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args) return m_data; } -void dev::eth::upgradeDatabase(std::string const& _basePath) +void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash) { std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath; @@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath) { auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; - auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash; string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(databaseVersion); diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 0dfe8509b..df48269ec 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -42,7 +43,7 @@ namespace eth */ bytes parseData(std::string const& _args); -void upgradeDatabase(std::string const& _basePath); +void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash); } } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 7d63ed165..15d39bded 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); -#if ETH_USING_ETHASH // TODO: move into ProofOfWork. - res["nonce"] = toJS(_bi.proof.nonce); - res["seedHash"] = toJS(_bi.proofCache()); -#endif +// res["nonce"] = toJS(_bi.proof.nonce); +// res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..624a73e54 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. +template +Json::Value toJson(BlockHeaderPolished const& _bh) +{ + Json::Value res; + if (_bh) + { + res = toJson(static_cast(_bh)); + for (auto const& i: _bh.jsInfo()) + res[i.first] = i.second; + } + return res; +} + } namespace shh diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 1743882e5..061b5ae79 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -24,7 +24,6 @@ #include #include "../JsonSpiritHeaders.h" #include -#include #include #include #include "../TestHelper.h" @@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - Ethash::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 452163061..e3f8ac29f 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. From 5ee3e8e5fc052ea6536c86cc40cb1a8c50191c4c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:29:03 +0200 Subject: [PATCH 043/113] All fields of BlockInfo now private. --- alethzero/MainWin.cpp | 34 +++--- ethminer/MinerAux.h | 4 +- evmjit/libevmjit-cpp/JitVM.cpp | 6 +- evmjit/libevmjit/RuntimeManager.cpp | 6 +- exp/main.cpp | 6 +- libethcore/BasicAuthority.cpp | 8 +- libethcore/BlockInfo.cpp | 104 ++++++++--------- libethcore/BlockInfo.h | 91 +++++++++------ libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 40 +++---- libethcore/EthashAux.cpp | 2 +- libethereum/BasicGasPricer.cpp | 6 +- libethereum/BlockChain.cpp | 78 +++++-------- libethereum/BlockChain.h | 2 +- libethereum/BlockChainSync.cpp | 6 +- libethereum/BlockQueue.cpp | 50 ++++---- libethereum/Executive.cpp | 10 +- libethereum/State.cpp | 133 +++++++++++----------- libethereum/State.h | 2 +- libevm/ExtVMFace.h | 4 +- libevm/VM.cpp | 10 +- libtestutils/BlockChainLoader.cpp | 2 +- libweb3jsonrpc/JsonHelper.cpp | 22 ++-- test/TestHelper.cpp | 6 +- test/libethereum/ClientBase.cpp | 18 +-- test/libethereum/blockchain.cpp | 78 ++++++------- test/libethereum/genesis.cpp | 2 +- test/libevm/vm.cpp | 12 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- third/MainWin.cpp | 2 +- 30 files changed, 378 insertions(+), 370 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2ee8928f5..ad8f5528c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,7 +189,7 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; @@ -1629,7 +1629,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1706,7 +1706,7 @@ void Main::on_blocks_currentItemChanged() if (item->data(Qt::UserRole + 1).isNull()) { char timestamp[64]; - time_t rawTime = (time_t)(uint64_t)info.timestamp; + time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; s << "

#" << info.number; @@ -1714,7 +1714,7 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; - s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "" << "
"; + s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; @@ -1724,7 +1724,7 @@ void Main::on_blocks_currentItemChanged() { auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; - s << "
Parent: " << info.parentHash << "" << "
"; + s << "
Parent: " << info.parentHash() << "" << "
"; } else { @@ -1732,20 +1732,20 @@ void Main::on_blocks_currentItemChanged() s << "
Parent: It was a virgin birth
"; } // s << "
Bloom: " << details.bloom << ""; - if (!!info.logBloom) - s << "
Log Bloom: " << info.logBloom << "
"; + if (!!info.logBloom()) + s << "
Log Bloom: " << info.logBloom() << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; - s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Parent: " << uncle.parentHash() << "" << ""; s << line << "Number: " << uncle.number << "" << ""; - s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; @@ -1754,20 +1754,20 @@ void Main::on_blocks_currentItemChanged() auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } - if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; + if (info.parentHash()) + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; else s << "
Pre: Nothing is before Phil" << "
"; - s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; + s << "
Receipts: @" << info.receiptsRoot() << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Post: " << info.stateRoot() << "" << "
"; s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } @@ -1807,7 +1807,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 61fde605d..0d227b1ef 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -398,8 +398,8 @@ private: void doInitDAG(unsigned _n) { BlockInfo bi; - bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; + bi.number() = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 2fb2a0e67..4e1fb66ea 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -24,7 +24,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index d48b64bb1..b2c15d7ae 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,7 +1,7 @@ #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" #include "Stack.h" @@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; + case RuntimeData::Timestamp: return "block.timestamp()"; case RuntimeData::Code: return "code.ptr"; case RuntimeData::CodeSize: return "code.size"; } diff --git a/exp/main.cpp b/exp/main.cpp index 4a35068f1..0b740e526 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,8 +85,8 @@ int main() BlockInfo bi; bi.difficulty = c_genesisDifficulty; bi.gasLimit = c_genesisGasLimit; - bi.number = 1; - bi.parentHash = sha3("parentHash"); + bi.number() = 1; + bi.parentHash() = sha3("parentHash"); bytes sealedData; @@ -329,7 +329,7 @@ int main() mine(s, bc, se); bytes minedBlock = s.blockData(); - cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot(); bc.import(minedBlock, stateDB); cnote << bc; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 22da67080..7ef3dd21e 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -44,19 +44,19 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri m_sig = _header[BlockInfo::BasicFields].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); BOOST_THROW_EXCEPTION(ex); } } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 64961bc40..266f57cc8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -BlockInfo::BlockInfo(): timestamp(Invalid256) +BlockInfo::BlockInfo(): m_timestamp(Invalid256) { } @@ -45,26 +45,26 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, void BlockInfo::clear() { - parentHash = h256(); - sha3Uncles = EmptyListSHA3; - coinbaseAddress = Address(); - stateRoot = EmptyTrie; - transactionsRoot = EmptyTrie; - receiptsRoot = EmptyTrie; - logBloom = LogBloom(); - difficulty = 0; - number = 0; - gasLimit = 0; - gasUsed = 0; - timestamp = 0; - extraData.clear(); + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_coinbaseAddress = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = 0; + m_extraData.clear(); noteDirty(); } h256 const& BlockInfo::boundary() const { - if (!m_boundary && difficulty) - m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); + if (!m_boundary && m_difficulty) + m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty); return m_boundary; } @@ -81,8 +81,8 @@ h256 const& BlockInfo::hashWithout() const void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << gasLimit << gasUsed << timestamp << extraData; + _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; } h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) @@ -110,19 +110,19 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { - parentHash = _header[field = 0].toHash(RLP::VeryStrict); - sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); - coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); - stateRoot = _header[field = 3].toHash(RLP::VeryStrict); - transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); - receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); - logBloom = _header[field = 6].toHash(RLP::VeryStrict); - difficulty = _header[field = 7].toInt(); - number = _header[field = 8].toInt(); - gasLimit = _header[field = 9].toInt(); - gasUsed = _header[field = 10].toInt(); - timestamp = _header[field = 11].toInt(); - extraData = _header[field = 12].toBytes(); + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toInt(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toInt(); + m_extraData = _header[field = 12].toBytes(); } catch (Exception const& _e) { @@ -130,11 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) throw; } - if (number > ~(unsigned)0) + if (m_number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing && gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); + if (_s != CheckNothing && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -147,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); - if (transactionsRoot != expectedRoot) + if (m_transactionsRoot != expectedRoot) { MemoryDB tm; GenericTrieDB transactionsTrie(&tm); @@ -172,52 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) cdebug << toHex(t); - BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot)); + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); - if (sha3Uncles != sha3(root[2].data())) + if (m_sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } void BlockInfo::populateFromParent(BlockInfo const& _parent) { - stateRoot = _parent.stateRoot; - number = _parent.number + 1; - gasLimit = selectGasLimit(_parent); - gasUsed = 0; - difficulty = calculateDifficulty(_parent); - parentHash = _parent.hash(); + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_gasLimit = selectGasLimit(_parent); + m_gasUsed = 0; + m_difficulty = calculateDifficulty(_parent); + m_parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return c_genesisGasLimit; else // target minimum of 3141592 - if (_parent.gasLimit < c_genesisGasLimit) - return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + if (_parent.m_gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return (u256)c_genesisDifficulty; else - return max(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor))); + return max(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); } void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check timestamp is after previous timestamp. - if (parentHash) + if (m_parentHash) { - if (timestamp <= _parent.timestamp) + if (m_timestamp <= _parent.m_timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); - if (number != _parent.number + 1) + if (m_number != _parent.m_number + 1) BOOST_THROW_EXCEPTION(InvalidNumber()); } } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b00fa73fb..67a5397f4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -81,21 +81,6 @@ struct BlockInfo public: static const unsigned BasicFields = 13; - // TODO: make them all private! - h256 parentHash; - h256 sha3Uncles; - Address coinbaseAddress; - h256 stateRoot; - h256 transactionsRoot; - h256 receiptsRoot; - LogBloom logBloom; - u256 difficulty; // TODO: pull out into BlockHeader - u256 number; - u256 gasLimit; - u256 gasUsed; - u256 timestamp = Invalid256; - bytes extraData; - BlockInfo(); explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} @@ -104,23 +89,23 @@ public: static h256 headerHashFromBlock(bytesConstRef _block); static RLP extractHeader(bytesConstRef _block); - explicit operator bool() const { return timestamp != Invalid256; } + explicit operator bool() const { return m_timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { - return parentHash == _cmp.parentHash && - sha3Uncles == _cmp.sha3Uncles && - coinbaseAddress == _cmp.coinbaseAddress && - stateRoot == _cmp.stateRoot && - transactionsRoot == _cmp.transactionsRoot && - receiptsRoot == _cmp.receiptsRoot && - logBloom == _cmp.logBloom && - difficulty == _cmp.difficulty && - number == _cmp.number && - gasLimit == _cmp.gasLimit && - gasUsed == _cmp.gasUsed && - timestamp == _cmp.timestamp && - extraData == _cmp.extraData; + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_coinbaseAddress == _cmp.coinbaseAddress() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } @@ -132,6 +117,31 @@ public: u256 selectGasLimit(BlockInfo const& _parent) const; h256 const& boundary() const; + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); } + void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + + Address const& coinbaseAddress() const { return m_coinbaseAddress; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& timestamp() const { return m_timestamp; } + bytes const& extraData() const { return m_extraData; } + + u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader + /// sha3 of the header only. h256 const& hashWithout() const; h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } @@ -145,6 +155,21 @@ protected: mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + h256 m_parentHash; + h256 m_sha3Uncles; + Address m_coinbaseAddress; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + u256 m_number; + u256 m_gasLimit; + u256 m_gasUsed; + u256 m_timestamp = Invalid256; + bytes m_extraData; + + u256 m_difficulty; // TODO: pull out into BlockHeader + private: mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty @@ -152,9 +177,9 @@ private: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp; + _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); return _out; } @@ -191,7 +216,7 @@ public: // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { - if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); BlockInfoSub::verifyParent(_parent); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 499854584..05cc45280 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -124,7 +124,7 @@ static void badBlockInfo(BlockInfo const& _bi, string const& _err) ss << c_space << endl; ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_space << endl; - string bin = toString(_bi.number); + string bin = toString(_bi.number()); ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; ss << c_space << endl; ss << c_line; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 128822b80..ee483aa8b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ namespace eth h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); + m_seedHash = EthashAux::seedHash((unsigned)m_number); return m_seedHash; } @@ -72,7 +72,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_nonce(m_nonce); @@ -81,42 +81,42 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } if (_s != CheckNothing) { - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + if (m_difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) ); - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + if (m_gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) ); - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + if (m_number && m_extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size()))); } } void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) { // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + if (m_difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty)); - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); + if (m_gasLimit < c_minGasLimit || + m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor || + m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)); } void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) @@ -126,7 +126,7 @@ void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) bool Ethash::BlockHeaderRaw::preVerify() const { - if (number >= ETHASH_EPOCH_LENGTH * 2048) + if (m_number >= ETHASH_EPOCH_LENGTH * 2048) return false; bool ret = !!ethash_quick_check_difficulty( @@ -162,7 +162,7 @@ bool Ethash::BlockHeaderRaw::verify() const cwarn << "headerHash:" << hashWithout(); cwarn << "nonce:" << m_nonce; cwarn << "mixHash:" << m_mixHash; - cwarn << "difficulty:" << difficulty; + cwarn << "difficulty:" << m_difficulty; cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; @@ -290,7 +290,7 @@ public: m_farm.setWork(m_sealing); m_farm.start(m_sealer); m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number); + Ethash::ensurePrecomputed((unsigned)_bi.number()); } void onSealGenerated(std::function const& _f) override { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index c511978db..763bea417 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,7 +63,7 @@ EthashAux* EthashAux::get() uint64_t EthashAux::cacheSize(BlockInfo const& _header) { - return ethash_get_cachesize((uint64_t)_header.number); + return ethash_get_cachesize((uint64_t)_header.number()); } uint64_t EthashAux::dataSize(uint64_t _blockNumber) diff --git a/libethereum/BasicGasPricer.cpp b/libethereum/BasicGasPricer.cpp index 145d23594..b957966f8 100644 --- a/libethereum/BasicGasPricer.cpp +++ b/libethereum/BasicGasPricer.cpp @@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; h256 p = _bc.currentHash(); - m_gasPerBlock = _bc.info(p).gasLimit; + m_gasPerBlock = _bc.info(p).gasLimit(); map dist; u256 total = 0; @@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc) while (c < 1000 && p) { BlockInfo bi = _bc.info(p); - if (bi.transactionsRoot != EmptyTrie) + if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); @@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc) i++; } } - p = bi.parentHash; + p = bi.parentHash(); ++c; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aae8cbd10..b696c77bd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) { try { BlockInfo d(bytesConstRef(it->value())); - _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; + _out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; } catch (...) { cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); @@ -293,11 +293,11 @@ void BlockChain::rebuild(std::string const& _path, std::function parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1); + cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); return; } lastHash = bi.hash(); @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -461,21 +461,21 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Work out its number as the parent's number + 1 - if (!isKnown(_block.info.parentHash)) + if (!isKnown(_block.info.parentHash())) { - clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash(); // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_block.info.parentHash); + auto pd = details(_block.info.parentHash()); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_block.info.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; + auto parentBlock = block(_block.info.parentHash()); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash()); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number(); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -483,9 +483,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Check it's not crazy - if (_block.info.timestamp > (u256)time(0)) + if (_block.info.timestamp() > (u256)time(0)) { - clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } @@ -543,9 +543,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_block.info.parentHash); + details(_block.info.parentHash()); DEV_WRITE_GUARDED(x_details) - m_details[_block.info.parentHash].children.push_back(_block.info.hash()); + m_details[_block.info.parentHash()].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); @@ -554,9 +554,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp())); - extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); @@ -585,10 +585,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif - // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; h256 common; @@ -599,7 +599,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash()); route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be @@ -630,15 +630,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Collate logs into blooms. h256s alteredBlooms; { - LogBloom blockBloom = tbi.logBloom; - blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); + LogBloom blockBloom = tbi.logBloom(); + blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref())); // Pre-memoize everything we need before locking x_blocksBlooms - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) blocksBlooms(chunkId(level, index / c_bloomIndexSize)); WriteGuard l(x_blocksBlooms); - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) { unsigned i = index / c_bloomIndexSize; unsigned o = index % c_bloomIndexSize; @@ -661,23 +661,23 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& ReadGuard l1(x_blocksBlooms); for (auto const& h: alteredBlooms) extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); - extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); + extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); } // FINALLY! change our best hash. { newLastBlockHash = _block.info.hash(); - newLastBlockNumber = (unsigned)_block.info.number; + newLastBlockNumber = (unsigned)_block.info.number(); } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; #if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif } @@ -750,7 +750,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& checkBest = t.elapsed(); if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number(); cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; @@ -758,7 +758,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; cnote << " " << _block.transactions.size() << " transactions"; - cnote << " " << _block.info.gasUsed << " gas used"; + cnote << " " << _block.info.gasUsed() << " gas used"; } #endif @@ -861,7 +861,7 @@ void BlockChain::rescue(OverlayDB& _db) cout << "extras..." << flush; details(h); cout << "state..." << flush; - if (_db.exists(bi.stateRoot)) + if (_db.exists(bi.stateRoot())) break; } catch (...) {} @@ -1233,19 +1233,3 @@ State BlockChain::genesisState(OverlayDB const& _db) return ret; } - - - - - - - - - - - - - - - - diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50965f2b6..3ff85c8a6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -391,7 +391,7 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash)); + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index ed022fb75..2141c4587 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr _peer) unsigned BlockChainSync::estimatedHashes() const { BlockInfo block = host().chain().info(); - time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp(); time_t now = time(0); unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) @@ -220,9 +220,9 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); - if (bi.number > maxUnknownNumber) + if (bi.number() > maxUnknownNumber) { - maxUnknownNumber = bi.number; + maxUnknownNumber = bi.number(); maxUnknown = h; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6b400b236..c9ee4c1cf 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,8 +101,8 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.sha3Uncles = work.hash; - bi.parentHash = work.parentHash; + bi.setSha3Uncles(work.hash); + bi.setParentHash(work.parentHash); m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.sha3Uncles == work.hash) + if (it->verified.info.sha3Uncles() == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,11 +136,11 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash) { // we're next! m_verifying.pop_front(); - if (m_knownBad.count(res.verified.info.parentHash)) + if (m_knownBad.count(res.verified.info.parentHash())) { m_readySet.erase(res.verified.info.hash()); m_knownBad.insert(res.verified.info.hash()); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.sha3Uncles == work.hash) + if (i.verified.info.sha3Uncles() == work.hash) { i = move(res); goto OK; @@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() { while (!m_verifying.empty() && !m_verifying.front().blockData.empty()) { - if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + if (m_knownBad.count(m_verifying.front().verified.info.parentHash())) { m_readySet.erase(m_verifying.front().verified.info.hash()); m_knownBad.insert(m_verifying.front().verified.info.hash()); @@ -213,7 +213,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) return ImportResult::Malformed; } - clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash(); // Check block doesn't already exist first! if (m_bc->isKnown(h)) @@ -227,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // Check it's not in the future (void)_isOurs; - if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) + if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/) { - m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); + m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes()))); char buf[24]; - time_t bit = (unsigned)bi.timestamp; + time_t bit = (unsigned)bi.timestamp(); if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails - clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp() << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); + m_difficulty += bi.difficulty(); + bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash()); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. - if (m_knownBad.count(bi.parentHash)) + if (m_knownBad.count(bi.parentHash())) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash())) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; - m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash(); + m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_unknownCount++; return ImportResult::UnknownParent; @@ -268,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash(), _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_knownCount++; noteReady_WITH_LOCK(h); @@ -295,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::vector oldVerified; swap(m_verified, oldVerified); for (auto& b: oldVerified) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash())) { m_knownBad.insert(b.verified.info.hash()); m_readySet.erase(b.verified.info.hash()); @@ -321,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles())) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles(); m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); @@ -460,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; + m_drainingDifficulty += bs.verified.info.difficulty(); m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 866c9c8f9..e58e1a8c6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), + m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)), m_depth(_level) {} @@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction) // Avoid transactions that would take us beyond the block gas limit. u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) + if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit()) { - clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; - BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas())); } // Check gas cost is enough. @@ -403,7 +403,7 @@ void Executive::finalize() m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); - m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); + m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned); // Suicides... if (m_ext) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ee2078a07..64daaf5f8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -105,7 +105,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock.clear(); m_currentBlock.clear(); -// assert(m_state.root() == m_previousBlock.stateRoot); +// assert(m_state.root() == m_previousBlock.stateRoot()); paranoia("end of normal construction.", true); } @@ -123,16 +123,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& auto b = _bc.block(_h); BlockInfo bi(b); - if (bi.number) + if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + BlockInfo bip(_bc.block(bi.parentHash())); + sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. - m_ourAddress = bi.coinbaseAddress; + m_ourAddress = bi.coinbaseAddress(); Timer t; auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); @@ -338,9 +338,9 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - if (m_db.lookup(bi.stateRoot).empty()) + if (m_db.lookup(bi.stateRoot()).empty()) { - cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; + cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); @@ -357,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash()); // push back for later replay. - bi.populate(_bc.block(bi.parentHash)); // move to parent. + bi.populate(_bc.block(bi.parentHash())); // move to parent. } m_previousBlock = bi; @@ -402,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif // Check family: - BlockInfo biParent = _bc.info(_block.info.parentHash); + BlockInfo biParent = _bc.info(_block.info.parentHash()); _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -411,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif BlockInfo biGrandParent; - if (biParent.number) - biGrandParent = _bc.info(biParent.parentHash); + if (biParent.number()) + biGrandParent = _bc.info(biParent.parentHash()); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo()); + sync(_bc, _block.info.parentHash(), BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -462,17 +462,15 @@ void State::resetCurrent() m_cache.clear(); m_touched.clear(); m_currentBlock = BlockInfo(); - m_currentBlock.coinbaseAddress = m_ourAddress; - m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); - m_currentBlock.transactionsRoot = h256(); - m_currentBlock.sha3Uncles = h256(); + m_currentBlock.setCoinbaseAddress(m_ourAddress); + m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0))); m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); m_committedToMine = false; @@ -538,7 +536,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu catch (BlockGasLimitReached const& e) { bigint const& got = *boost::get_error_info(e); - if (got > m_currentBlock.gasLimit) + if (got > m_currentBlock.gasLimit()) { clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; _tq.drop(t.sha3()); @@ -583,7 +581,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number()); string ret; unsigned i = 0; @@ -604,12 +602,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == _block.info.parentHash); - assert(m_currentBlock.parentHash == _block.info.parentHash); - assert(rootHash() == m_previousBlock.stateRoot); + assert(m_previousBlock.hash() == _block.info.parentHash()); + assert(m_currentBlock.parentHash() == _block.info.parentHash()); + assert(rootHash() == m_previousBlock.stateRoot()); #endif - if (m_currentBlock.parentHash != m_previousBlock.hash()) + if (m_currentBlock.parentHash() != m_previousBlock.hash()) // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); @@ -622,7 +620,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) LastHashes lh; DEV_TIMED_ABOVE("lastHashes", 500) - lh = _bc.lastHashes((unsigned)m_previousBlock.number); + lh = _bc.lastHashes((unsigned)m_previousBlock.number()); RLP rlp(_block.block); @@ -651,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) } h256 receiptsRoot; - DEV_TIMED_ABOVE("receiptsRoot", 500) + DEV_TIMED_ABOVE(".receiptsRoot()", 500) receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) + if (receiptsRoot != m_currentBlock.receiptsRoot()) { InvalidReceiptsStateRoot ex; - ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot()); ex << errinfo_receipts(receipts); ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } - if (m_currentBlock.logBloom != logBloom()) + if (m_currentBlock.logBloom() != logBloom()) { InvalidLogBloom ex; - ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom()); ex << errinfo_receipts(receipts); BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. - u256 tdIncrease = m_currentBlock.difficulty; + u256 tdIncrease = m_currentBlock.difficulty(); // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) @@ -686,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) vector rewarded; h256Hash excluded; DEV_TIMED_ABOVE("allKin", 500) - excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; @@ -710,22 +708,22 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) + if (!_bc.isKnown(uncle.parentHash())) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + uncleParent = BlockInfo(_bc.block(uncle.parentHash())); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7) { UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } - else if (uncle.number == m_currentBlock.number) + else if (uncle.number() == m_currentBlock.number()) { UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } uncle.verifyParent(uncleParent); @@ -748,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash()) { m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot())); } - if (m_currentBlock.gasUsed != gasUsed()) + if (m_currentBlock.gasUsed() != gasUsed()) { // Rollback the trie. m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed()))); } return tdIncrease; @@ -772,7 +770,7 @@ void State::cleanup(bool _fullCommit) // Commit the new trie to disk. if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -786,7 +784,7 @@ void State::cleanup(bool _fullCommit) m_db.commit(); if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -806,7 +804,7 @@ void State::uncommitToMine() { m_cache.clear(); if (!m_transactions.size()) - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); else m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; @@ -878,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock.number != 0) + if (m_previousBlock.number() != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); - auto p = m_previousBlock.parentHash; +// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl; + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; @@ -926,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = hash256(transactionsMap); - m_currentBlock.receiptsRoot = hash256(receiptsMap); - m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); - // Apply rewards last of all. applyRewards(uncleBlockHeaders); @@ -941,12 +934,18 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // cnote << m_state; // cnote << *this; - m_currentBlock.gasUsed = gasUsed(); - m_currentBlock.stateRoot = m_state.root(); - m_currentBlock.parentHash = m_previousBlock.hash(); - m_currentBlock.extraData = _extraData; - if (m_currentBlock.extraData.size() > 32) - m_currentBlock.extraData.resize(32); + m_currentBlock.setLogBloom(logBloom()); + m_currentBlock.setGasUsed(gasUsed()); + m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root()); + + m_currentBlock.setParentHash(m_previousBlock.hash()); + m_currentBlock.setExtraData(_extraData); + if (m_currentBlock.extraData().size() > 32) + { + auto ed = m_currentBlock.extraData(); + ed.resize(32); + m_currentBlock.setExtraData(ed); + } m_committedToMine = true; } @@ -967,13 +966,13 @@ bool State::sealBlock(bytesConstRef _header) ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); - cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; + cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")"; // TODO: move into Sealer StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), "", // Can't give the nonce here. "", //TODO: chain head hash here ?? - m_currentBlock.parentHash.abridged() + m_currentBlock.parentHash().abridged() ); // Quickly reset the transactions. @@ -1270,7 +1269,7 @@ State State::fromPending(unsigned _i) const ret.m_cache.clear(); _i = min(_i, m_transactions.size()); if (!_i) - ret.m_state.setRoot(m_previousBlock.stateRoot); + ret.m_state.setRoot(m_previousBlock.stateRoot()); else ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) @@ -1287,10 +1286,10 @@ void State::applyRewards(vector const& _uncleBlockHeaders) u256 r = m_blockReward; for (auto const& i: _uncleBlockHeaders) { - addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8); + addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8); r += m_blockReward / 32; } - addBalance(m_currentBlock.coinbaseAddress, r); + addBalance(m_currentBlock.coinbaseAddress(), r); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) diff --git a/libethereum/State.h b/libethereum/State.h index 805215ee5..e2bda6f24 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } + u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); } /// Check if the address is in use. bool addressInUse(Address _address) const; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..a5c45af26 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -83,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry ): LogEntry(_le), blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), + blockNumber((BlockNumber)_bi.number()), transactionHash(_th), transactionIndex(_ti), logIndex(_li), @@ -205,7 +205,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } + h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2b2ada0ae..f95481c54 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress()); break; case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); + m_stack.push_back(_ext.currentBlock.timestamp()); break; case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); + m_stack.push_back(_ext.currentBlock.number()); break; case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); + m_stack.push_back(_ext.currentBlock.difficulty()); break; case Instruction::GASLIMIT: - m_stack.push_back(_ext.currentBlock.gasLimit); + m_stack.push_back(_ext.currentBlock.gasLimit()); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libtestutils/BlockChainLoader.cpp b/libtestutils/BlockChainLoader.cpp index e6c47e2fe..7e08243af 100644 --- a/libtestutils/BlockChainLoader.cpp +++ b/libtestutils/BlockChainLoader.cpp @@ -36,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) // load genesisBlock m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); - assert(m_state.rootHash() == m_bc->info().stateRoot); + assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks for (auto const& block: _json["blocks"]) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 15d39bded..fae12708c 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -88,18 +88,18 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) if (_bi) { res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["parentHash"] = toJS(_bi.parentHash()); + res["sha3Uncles"] = toJS(_bi.sha3Uncles()); + res["miner"] = toJS(_bi.coinbaseAddress()); + res["stateRoot"] = toJS(_bi.stateRoot()); + res["transactionsRoot"] = toJS(_bi.transactionsRoot()); res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); + res["number"] = toJS(_bi.number()); res["gasUsed"] = toJS(_bi.gasUsed); res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["logsBloom"] = toJS(_bi.logBloom); + res["timestamp"] = toJS(_bi.timestamp()); + res["extraData"] = toJS(_bi.extraData()); + res["logsBloom"] = toJS(_bi.logBloom()); res["target"] = toJS(_bi.boundary()); // TODO: move into ProofOfWork. @@ -140,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number())); } return res; } @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()); + res["stateRoot"] = toJS(_t.stateRoot()()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b43c4db51..bae980a7e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -151,12 +151,12 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); m_environment.currentBlock.number = toInt(_o["currentNumber"]); m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 9ee93779e..7dbc5c91e 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(blocks) u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString()); h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString())); h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); - ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom); - ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress); + ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); + ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), - _blockInfo.extraData.begin(), - _blockInfo.extraData.end() + _blockInfo.extraData().begin(), + _blockInfo.extraData().end() ); ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); @@ -132,11 +132,11 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); - ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp); - ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles); + ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); + ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; BlockInfo blockInfo = _client.blockInfo(blockHash); diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 20f60618f..cf44dfd9f 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -66,7 +66,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,9 +76,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot = trueState.rootHash(); + biGenesisBlock.stateRoot() = trueState.rootHash(); else - TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -125,7 +125,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TransientDirectory td_stateDB, td_bc; BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -225,7 +225,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); updatePoW(current_BlockHeader); } @@ -302,7 +302,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (o.count("expect") > 0) { stateOptionsMap expectStateMap; - State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); @@ -313,7 +313,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section - State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); }//_fillin @@ -374,19 +374,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); @@ -551,7 +551,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp = (u256)time(0); + uncleBlockFromFields.timestamp() = (u256)time(0); cnote << "uncle block n = " << toString(uncleBlockFromFields.number); if (_vBiBlocks.size() > 2) { @@ -568,15 +568,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash; - uncleBlockFromFields.stateRoot = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot; + uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); + uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); if (overwrite == "timestamp") { - uncleBlockFromFields.timestamp = toInt(uncleHeaderObj["timestamp"]); + uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); } } @@ -660,19 +660,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { BlockInfo tmp = _header; if (ho.count("parentHash")) - tmp.parentHash = h256(ho["parentHash"].get_str()); + tmp.parentHash() = h256(ho["parentHash"].get_str()); if (ho.count("uncleHash")) - tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); if (ho.count("coinbase")) - tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); if (ho.count("stateRoot")) - tmp.stateRoot = h256(ho["stateRoot"].get_str()); + tmp.stateRoot() = h256(ho["stateRoot"].get_str()); if (ho.count("transactionsTrie")) - tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); if (ho.count("receiptTrie")) - tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); if (ho.count("bloom")) - tmp.logBloom = LogBloom(ho["bloom"].get_str()); + tmp.logBloom() = LogBloom(ho["bloom"].get_str()); if (ho.count("difficulty")) tmp.difficulty = toInt(ho["difficulty"]); if (ho.count("number")) @@ -682,9 +682,9 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) if (ho.count("gasUsed")) tmp.gasUsed = toInt(ho["gasUsed"]); if (ho.count("timestamp")) - tmp.timestamp = toInt(ho["timestamp"]); + tmp.timestamp() = toInt(ho["timestamp"]); if (ho.count("extraData")) - tmp.extraData = importByteArray(ho["extraData"].get_str()); + tmp.extraData() = importByteArray(ho["extraData"].get_str()); // find new valid nonce if (tmp != _header && tmp.difficulty) @@ -751,19 +751,19 @@ mArray writeTransactionsToJson(Transactions const& txs) mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) { - _o["parentHash"] = toString(_bi.parentHash); - _o["uncleHash"] = toString(_bi.sha3Uncles); - _o["coinbase"] = toString(_bi.coinbaseAddress); - _o["stateRoot"] = toString(_bi.stateRoot); - _o["transactionsTrie"] = toString(_bi.transactionsRoot); - _o["receiptTrie"] = toString(_bi.receiptsRoot); - _o["bloom"] = toString(_bi.logBloom); + _o["parentHash"] = toString(_bi.parentHash()); + _o["uncleHash"] = toString(_bi.sha3Uncles()); + _o["coinbase"] = toString(_bi.coinbaseAddress()); + _o["stateRoot"] = toString(_bi.stateRoot()); + _o["transactionsTrie"] = toString(_bi.transactionsRoot()); + _o["receiptTrie"] = toString(_bi.receiptsRoot()); + _o["bloom"] = toString(_bi.logBloom()); _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); - _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); + _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); _o["hash"] = toString(_bi.hash()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 02ff4517a..2d5a2faa6 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index fdfb180fb..28b2e43ab 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -83,10 +83,10 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st mObject FakeExtVM::exportEnv() { mObject ret; - ret["previousHash"] = toString(currentBlock.parentHash); + ret["previousHash"] = toString(currentBlock.parentHash()); ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); - ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp, HexPrefix::Add, 1); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); return ret; @@ -102,13 +102,13 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash = h256(_o["previousHash"].get_str()); + currentBlock.parentHash() = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } mObject FakeExtVM::exportState() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 9f806347e..be44ea009 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1187,7 +1187,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " return block.timestamp() == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/third/MainWin.cpp b/third/MainWin.cpp index f2a90cc0b..a3b05572f 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From f663801126fd23efd838fe88e66571384950e56e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:34:11 +0200 Subject: [PATCH 044/113] Minor fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ec37302a2..357926d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -98,7 +98,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + bc().rescue(m_stateDB); m_gp->update(bc()); From ef0d9a96fb18ae8efb3bb84d775dcd73f49c4c4a Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 11:43:23 +0200 Subject: [PATCH 045/113] fixed build --- evmjit/libevmjit-cpp/JitVM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 4e1fb66ea..d96da87c1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -42,10 +42,10 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); - m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); - m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); - m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); + m_data.difficulty = eth2jit(_ext.currentBlock.difficulty()); + m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit()); + m_data.number = static_cast(_ext.currentBlock.number()); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); From e6d2200ccacb16997eb855b8d84a62c0fdc2246a Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 16:45:23 +0200 Subject: [PATCH 046/113] mix working --- CMakeLists.txt | 28 +++++++------- alethzero/MainWin.cpp | 53 ++++++++++++++------------- alethzero/MiningView.cpp | 4 +- alethzero/MiningView.h | 4 +- exp/CMakeLists.txt | 4 +- libethereum/BlockChain.cpp | 1 - libtestutils/BlockChainLoader.cpp | 3 +- libtestutils/StateLoader.cpp | 2 +- libtestutils/StateLoader.h | 2 + libweb3jsonrpc/JsonHelper.cpp | 8 ++-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libwebthree/WebThree.cpp | 2 +- mix/ClientModel.cpp | 4 +- mix/MixClient.cpp | 36 +++++++++--------- mix/MixClient.h | 36 +++++++++++++++--- 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 421dd1bb7..271f3ed65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) -# add_subdirectory(libweb3jsonrpc) + add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) -# add_subdirectory(libjsengine) -# add_subdirectory(libjsconsole) -# add_subdirectory(ethconsole) + add_subdirectory(libjsengine) + add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -434,31 +434,31 @@ add_subdirectory(libethcore) if (GENERAL) add_subdirectory(libevm) add_subdirectory(libethereum) -# add_subdirectory(libwebthree) + add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) -# add_subdirectory(ethminer) + add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) -# add_subdirectory(ethkey) + add_subdirectory(ethkey) endif () if (TESTS) -# add_subdirectory(libtestutils) -# add_subdirectory(test) + add_subdirectory(libtestutils) + add_subdirectory(test) if (JSONRPC) -# add_subdirectory(ethrpctest) + add_subdirectory(ethrpctest) endif () endif () if (TOOLS) -# add_subdirectory(rlp) -# add_subdirectory(abi) -# add_subdirectory(ethvm) -# add_subdirectory(eth) + add_subdirectory(rlp) + add_subdirectory(abi) + add_subdirectory(ethvm) + add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ad8f5528c..181772ddb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,9 +189,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; - auto block = CanonBlockChain::createGenesisBlock(); - cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl; @@ -208,13 +208,14 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); @@ -1124,7 +1125,7 @@ void Main::refreshMining() QString t; if (gp.first != EthashAux::NotGenerating) t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second); - MiningProgress p = ethereum()->miningProgress(); + WorkingProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining")); if (ethereum()->isMining() && p.hashes > 0) { @@ -1629,7 +1630,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1699,7 +1700,7 @@ void Main::on_blocks_currentItemChanged() auto details = ethereum()->blockChain().details(h); auto blockData = ethereum()->blockChain().block(h); auto block = RLP(blockData); - BlockInfo info(blockData); + Ethash::BlockHeader info(blockData); stringstream s; @@ -1709,21 +1710,21 @@ void Main::on_blocks_currentItemChanged() time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; - s << "

#" << info.number; + s << "

#" << info.number(); s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
"; s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; - s << "
Mix hash: " << info.mixHash << "" << "
"; - s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; - s << "
Difficulty: " << info.difficulty << "" << "
"; - if (info.number) + s << "
Mix hash: " << info.mixHash() << "" << "
"; + s << "
Nonce: " << info.nonce() << "" << "
"; + s << "
Hash w/o nonce: " << info.hashWithout() << "" << "
"; + s << "
Difficulty: " << info.difficulty() << "" << "
"; + if (info.number()) { - auto e = EthashAux::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce()); + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash() << "" << "
"; } else @@ -1740,19 +1741,19 @@ void Main::on_blocks_currentItemChanged() s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { - BlockInfo uncle = BlockInfo::fromHeader(u.data()); + Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; s << line << "Parent: " << uncle.parentHash() << "" << ""; - s << line << "Number: " << uncle.number << "" << ""; + s << line << "Number: " << uncle.number() << "" << ""; s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; - s << line << "Mix hash: " << uncle.mixHash << "" << ""; - s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Mix hash: " << uncle.mixHash() << "" << ""; + s << line << "Nonce: " << uncle.nonce() << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; - s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = EthashAux::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; + s << line << "Difficulty: " << uncle.difficulty() << "" << ""; + auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce()); + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash()) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; @@ -1764,7 +1765,7 @@ void Main::on_blocks_currentItemChanged() unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } s << "
Post: " << info.stateRoot() << "" << "
"; @@ -1807,7 +1808,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index e020408ea..fb9de0346 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MiningProgress; +using dev::eth::WorkingProgress; // functions using dev::toString; @@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MiningProgress const& _p) +void MiningView::appendStats(list const& _i, WorkingProgress const& _p) { (void)_p; if (_i.empty()) diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 65b9f2ec9..ae81a7cc4 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); + void appendStats(std::list const& _l, dev::eth::WorkingProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MiningProgress m_progress; + dev::eth::WorkingProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index b9f477385..0e19ac84d 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -21,10 +21,10 @@ if (READLINE_FOUND) endif() if (JSONRPC) -# target_link_libraries(${EXECUTABLE} web3jsonrpc) + target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -#target_link_libraries(${EXECUTABLE} webthree) +target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b696c77bd..03ab1b46a 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -137,7 +137,6 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map #include "BlockChainLoader.h" #include "StateLoader.h" #include "Common.h" @@ -35,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) m_state = sl.state(); // load genesisBlock - m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); + m_bc.reset(new FullBlockChain(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill)); assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks diff --git a/libtestutils/StateLoader.cpp b/libtestutils/StateLoader.cpp index 235f1c573..cd5c37e96 100644 --- a/libtestutils/StateLoader.cpp +++ b/libtestutils/StateLoader.cpp @@ -27,7 +27,7 @@ using namespace dev::eth; using namespace dev::test; StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): - m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty) + m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty) { for (string const& name: _json.getMemberNames()) { diff --git a/libtestutils/StateLoader.h b/libtestutils/StateLoader.h index 47eb26900..c66f53148 100644 --- a/libtestutils/StateLoader.h +++ b/libtestutils/StateLoader.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace dev { @@ -38,6 +39,7 @@ class StateLoader public: StateLoader(Json::Value const& _json, std::string const& _dbPath); eth::State const& state() const { return m_state; } + eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; } private: eth::State m_state; diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index fae12708c..54fde52e8 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -93,10 +93,10 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["miner"] = toJS(_bi.coinbaseAddress()); res["stateRoot"] = toJS(_bi.stateRoot()); res["transactionsRoot"] = toJS(_bi.transactionsRoot()); - res["difficulty"] = toJS(_bi.difficulty); + res["difficulty"] = toJS(_bi.difficulty()); res["number"] = toJS(_bi.number()); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); + res["gasUsed"] = toJS(_bi.gasUsed()); + res["gasLimit"] = toJS(_bi.gasLimit()); res["timestamp"] = toJS(_bi.timestamp()); res["extraData"] = toJS(_bi.extraData()); res["logsBloom"] = toJS(_bi.logBloom()); @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()()); + res["stateRoot"] = toJS(_t.stateRoot()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 3aff9cf23..bf49d3322 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str return true; } -dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +dev::eth::BlockChain const& WebThreeStubServer::bc() const { return m_web3.ethereum()->blockChain(); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4d545c90e..2860f852b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -34,7 +34,7 @@ namespace eth { class KeyManager; class TrivialGasPricer; -class CanonBlockChain; +class BlockChain; class BlockQueue; } @@ -89,7 +89,7 @@ private: private: h256 blockHash(std::string const& _blockNumberOrHash) const; - dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockChain const& bc() const; dev::eth::BlockQueue const& bq() const; dev::WebThreeDirect& m_web3; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 3c1dea40f..7889b5935 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect( Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) { - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); + m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr(), _dbPath, _we, 0)); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 90ff19feb..5c5f2f4cd 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); stringstream strGas; - strGas << blockInfo.gasUsed; + strGas << blockInfo.gasUsed(); stringstream strNumber; - strNumber << blockInfo.number; + strNumber << blockInfo.number(); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ea4686601..eef6ad6ec 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -24,12 +24,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include "Exceptions.h" using namespace std; @@ -45,22 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho namespace { +} -struct MixPow //dummy POW +MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot): + FullBlockChain(createGenesisBlock(_stateRoot), std::unordered_map(), _path, WithExisting::Kill) { - typedef int Solution; - static bool verify(BlockInfo const&) { return true; } -}; - } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(15) + block.appendList(13) << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); + << std::string(); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -78,7 +77,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,12 +89,13 @@ void MixClient::resetState(std::unordered_map const& _accounts SecureTrieDB accountState(&m_stateDB); accountState.init(); - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + dev::eth::commit(_accounts, accountState); h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); + State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + s.sync(bc()); + m_state = s; m_startState = m_state; WriteGuard lx(x_executions); m_executions.clear(); @@ -275,11 +274,14 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + + NoProof::BlockHeader h(m_state.info()); + RLPStream header; + h.streamRLP(header); + m_state.sealBlock(header.out()); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; } ExecutionResult MixClient::lastExecution() const @@ -383,9 +385,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MiningProgress MixClient::miningProgress() const +eth::WorkingProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::WorkingProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..279692de5 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,13 +33,40 @@ namespace dev { + namespace mix { -class MixBlockChain: public dev::eth::BlockChain +class NoProof +{ + class BlockHeaderRaw: public dev::eth::BlockInfo + { + public: + static const unsigned SealFields = 0; + + protected: + BlockHeaderRaw() = default; + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; } + void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; } + void streamRLPFields(RLPStream& _s) const { (void) _s; } + }; + +public: + + static std::string name() { return "NoProof"; } + static unsigned revision() { return 0; } + using BlockHeader = dev::eth::BlockHeaderPolished; + +private: + static AddressHash s_authorities; +}; + +class MixBlockChain: public dev::eth::FullBlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {} + MixBlockChain(std::string const& _path, h256 _stateRoot); static bytes createGenesisBlock(h256 _stateRoot); }; @@ -67,9 +95,7 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MiningProgress miningProgress() const override; - eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } - bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } + eth::WorkingProgress miningProgress() const override; virtual void flushTransactions() override {} /// @returns the last mined block information From 1820dbdcfcee55569ef302450fbb0f210ec39437 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 18:11:08 +0200 Subject: [PATCH 047/113] started tests refactoring --- libethcore/Common.h | 3 ++- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 9 +++++---- libethereum/BlockQueue.cpp | 2 +- libethereum/Client.cpp | 3 +-- mix/MixClient.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libethcore/dagger.cpp | 4 ++-- test/libethereum/ClientBase.cpp | 14 +++++++------- test/libethereum/genesis.cpp | 6 +++--- test/libethereum/stateOriginal.cpp | 5 +++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 5c0a0cc79..116e1d5ed 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -130,9 +130,10 @@ struct ImportRequirements TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, None = 0 }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 03ab1b46a..8a654fa51 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 3ff85c8a6..811da8609 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -118,12 +118,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -391,7 +391,8 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash())); + if ((_ir & ImportRequirements::Parent) != 0) + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c9ee4c1cf..d0ca34b1c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); } catch (...) { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 357926d03..d43f240b7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -84,10 +84,9 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database // until after the construction. m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); - m_preMine = State(m_stateDB); - m_postMine = State(m_stateDB); // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. m_preMine = bc().genesisState(m_stateDB); + m_postMine = m_preMine; m_bq.setChain(bc()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index eef6ad6ec..67f2a2507 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -279,7 +279,7 @@ void MixClient::mine() RLPStream header; h.streamRLP(header); m_state.sealBlock(header.out()); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bae980a7e..30f323369 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,7 +63,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 061b5ae79..8d4cba933 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); - BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); + BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); BOOST_REQUIRE_EQUAL(nonce, header.nonce); unsigned cacheSize(o["cache_size"].get_int()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 7dbc5c91e..a426ff53f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -119,21 +119,21 @@ BOOST_AUTO_TEST_CASE(blocks) h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); - ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); + ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty()); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), _blockInfo.extraData().begin(), _blockInfo.extraData().end() ); - ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); - ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); + ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit()); + ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed()); ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash()); - ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); - ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); - ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); + ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash()); + ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce()); + ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number()); ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 2d5a2faa6..39997572f 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,9 +60,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e3f8ac29f..163c89e50 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ BOOST_AUTO_TEST_CASE(Complex) Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; + OverlayDB stateDB = State::openDB(h256()); + CanonBlockChain bc; cout << bc; State s = bc.genesisState(stateDB); From ad50498faeab276967ef469b43ffad227265c310 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 20:53:58 +0200 Subject: [PATCH 048/113] eth working --- eth/main.cpp | 2 +- ethminer/MinerAux.h | 26 ++++++++++++-------------- libethcore/BlockInfo.h | 1 + libethereum/Client.h | 6 +++++- test/TestHelper.cpp | 17 ++++++++++++----- test/libethcore/dagger.cpp | 6 +++--- test/libethereum/ClientBase.cpp | 4 ++-- test/libethereum/gaspricer.cpp | 3 ++- test/libevm/vm.cpp | 10 +++++----- 9 files changed, 43 insertions(+), 32 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 8bbec9f00..4a8501a97 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1311,7 +1311,7 @@ int main(int argc, char** argv) { try { - CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); } catch (...) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 0d227b1ef..01083012f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -397,17 +397,16 @@ public: private: void doInitDAG(unsigned _n) { - BlockInfo bi; - bi.number() = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; - Ethash::prep(bi); + h256 seedHash = EthashAux::seedHash(_n); + cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl; + EthashAux::full(seedHash, true); exit(0); } void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) { - BlockInfo genesis; - genesis.difficulty = 1 << 18; + Ethash::BlockHeader genesis; + genesis.setDifficulty(1 << 18); cdebug << genesis.boundary(); GenericFarm f; @@ -417,17 +416,16 @@ private: cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; - Ethash::prep(genesis); + genesis.prep(); - genesis.difficulty = u256(1) << 63; - genesis.noteDirty(); + genesis.setDifficulty(u256(1) << 63); f.setWork(genesis); if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); - map results; + map results; uint64_t mean = 0; uint64_t innerMean = 0; for (unsigned i = 0; i <= _trials; ++i) @@ -488,9 +486,9 @@ private: Farm rpc(client); GenericFarm f; if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 67a5397f4..c310b3dd9 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -128,6 +128,7 @@ public: void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } Address const& coinbaseAddress() const { return m_coinbaseAddress; } h256 const& stateRoot() const { return m_stateRoot; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 73609bd71..4523d324b 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -77,7 +77,7 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); * @brief Main API hub for interfacing with Ethereum. * Not to be used directly - subclass. */ -class Client: public ClientBase, Worker +class Client: public ClientBase, protected Worker { public: /// New-style Constructor. @@ -342,6 +342,8 @@ public: init(_host, _dbPath, _forceAction, _networkId); } + virtual ~SpecialisedClient() { stopWorking(); } + /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } @@ -365,6 +367,8 @@ public: u256 _networkId = 0 ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + virtual ~EthashClient() { stopWorking(); } + /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. virtual std::tuple getEthashWork() override; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 30f323369..c29788b9f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -63,11 +64,17 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + Ethash::BlockHeader header(s.info); + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { - return completed = s.completeMine(sol); + header.m_mixHash = sol.mixHash; + header.m_nonce = sol.nonce; + RLPStream ret; + header.streamRLP(ret); + s.sealBlock(ret); + return true; }); f.setWork(s.info()); f.startCPU(); @@ -77,9 +84,9 @@ void mine(State& s, BlockChain const& _bc) void mine(BlockInfo& _bi) { - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { _bi.proof = sol; return completed = true; diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 8d4cba933..c3cd75b0d 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(basic_test) h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); - BOOST_REQUIRE_EQUAL(nonce, header.nonce); + BOOST_REQUIRE_EQUAL(nonce, header.nonce()); unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - EthashProofOfWork::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header.seedHash(), header.hashWithout(), header.nonce()); BOOST_REQUIRE_EQUAL(r.value, result); - BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); + BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash()); } } diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index a426ff53f..f9d83e9c6 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber); // blockInfo - auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void + auto compareBlockInfos = [](Json::Value const& _b, Ethash::BlockHeader _blockInfo) -> void { LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString())); Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString())); @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - BlockInfo blockInfo = _client.blockInfo(blockHash); + Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index ce49a4a20..050ab2d25 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer) std::shared_ptr gp(new TrivialGasPricer); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); - gp->update(BlockChain(bytes(), TransientDirectory().path(), WithExisting::Kill)); + gp->update(FullBlockChain(bytes(), StateDefinition(), TransientDirectory().path(), WithExisting::Kill)); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 28b2e43ab..badabd70c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number()), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -84,11 +84,11 @@ mObject FakeExtVM::exportEnv() { mObject ret; ret["previousHash"] = toString(currentBlock.parentHash()); - ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); + ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1); ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); - ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); - ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); + ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1); + ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1); return ret; } @@ -107,7 +107,7 @@ void FakeExtVM::importEnv(mObject& _o) lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } From 015835162108b41ddd943d6f09c96e5d124673a5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jul 2015 18:59:19 -0700 Subject: [PATCH 049/113] Modularise nonce, mix hash and seed hash. --- alethzero/MainWin.cpp | 4 +-- ethminer/MinerAux.h | 10 +++---- exp/main.cpp | 2 +- libethcore/BlockInfo.cpp | 45 +++++++++++++----------------- libethcore/BlockInfo.h | 26 +++++++++--------- libethcore/Common.cpp | 5 ++-- libethcore/Common.h | 1 + libethcore/Ethash.cpp | 52 ++++++++++++++++++++++++++++------- libethcore/Ethash.h | 16 +++++++++-- libethcore/EthashAux.cpp | 7 ++++- libethcore/EthashAux.h | 2 +- libethcore/ProofOfWork.h | 1 - libethereum/BlockChain.cpp | 8 +++--- libethereum/BlockQueue.cpp | 12 ++++---- libethereum/State.cpp | 8 +++--- libethereum/State.h | 4 +-- libweb3jsonrpc/JsonHelper.cpp | 7 +++-- mix/MixClient.cpp | 1 - test/TestHelper.cpp | 2 +- 19 files changed, 128 insertions(+), 85 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e48b58283..4655240e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1718,7 +1718,7 @@ void Main::on_blocks_currentItemChanged() s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { @@ -1749,7 +1749,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ff28132b1..5c6112743 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -254,17 +254,17 @@ public: bi.difficulty = u256(m); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bi.proof.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; exit(0); } catch (...) @@ -382,7 +382,7 @@ private: { BlockInfo bi; bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/exp/main.cpp b/exp/main.cpp index 88608f8cf..9884bd0e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -197,7 +197,7 @@ int main() bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, bi); + bi.proof = sol; return completed = true; }); f.setWork(bi); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index fec5b4678..c7acd9091 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -26,7 +26,6 @@ #include #include #include "EthashAux.h" -#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -57,22 +56,21 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - mixHash = h256(); - nonce = Nonce(); - m_hash = m_seedHash = h256(); + proof = ProofOfWork::Solution(); + m_proofCache = ProofOfWork::HeaderCache(); + m_hash = h256(); } -h256 const& BlockInfo::seedHash() const +ProofOfWork::HeaderCache const& BlockInfo::proofCache() const { - if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); - return m_seedHash; + ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); + return m_proofCache; } h256 const& BlockInfo::hash() const { if (!m_hash) - m_hash = headerHash(WithNonce); + m_hash = headerHash(WithProof); return m_hash; } @@ -90,20 +88,20 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const return ret; } -h256 BlockInfo::headerHash(IncludeNonce _n) const +h256 BlockInfo::headerHash(IncludeProof _n) const { RLPStream s; streamRLP(s, _n); return sha3(s.out()); } -void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const +void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const { - _s.appendList(_n == WithNonce ? 15 : 13) + _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithNonce) - _s << mixHash << nonce; + if (_n == WithProof) + proof.streamRLP(_s); } h256 BlockInfo::headerHash(bytesConstRef _block) @@ -116,12 +114,12 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); - m_seedHash = h256(); + m_proofCache = ProofOfWork::HeaderCache(); int field = 0; try { - if (_header.itemCount() != 15) + if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); @@ -136,8 +134,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - mixHash = _header[field = 13].toHash(RLP::VeryStrict); - nonce = _header[field = 14].toHash(RLP::VeryStrict); + proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -152,22 +149,18 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ProofOfWork::composeException(ex, *this); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); - ex << errinfo_seedHash(seedHash()); ex << errinfo_target(boundary()); - ex << errinfo_mixHash(mixHash); - Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce); - ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); BOOST_THROW_EXCEPTION(ex); } else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); + ProofOfWork::composeExceptionPre(ex, *this); BOOST_THROW_EXCEPTION(ex); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 79c12ebb4..b77c47c6b 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -24,16 +24,17 @@ #include #include #include "Common.h" +#include "ProofOfWork.h" namespace dev { namespace eth { -enum IncludeNonce +enum IncludeProof { - WithoutNonce = 0, - WithNonce = 1 + WithoutProof = 0, + WithProof = 1 }; enum Strictness @@ -82,8 +83,7 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - h256 mixHash; - Nonce nonce; + typename ProofOfWork::Solution proof; BlockInfo(); explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} @@ -112,14 +112,13 @@ public: gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && extraData == _cmp.extraData && - mixHash == _cmp.mixHash && - nonce == _cmp.nonce; + proof == _cmp.proof; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } void clear(); - void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); } + void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); @@ -130,16 +129,17 @@ public: u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - h256 const& seedHash() const; + ProofOfWork::HeaderCache const& proofCache() const; h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeNonce _n) const; - void streamRLP(RLPStream& _s, IncludeNonce _n) const; + h256 headerHash(IncludeProof _n) const; + void streamRLP(RLPStream& _s, IncludeProof _n) const; private: - mutable h256 m_seedHash; + + mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; @@ -148,7 +148,7 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; + _bi.gasUsed << " " << _bi.timestamp; return _out; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 618703e22..41cd1bba8 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -26,6 +26,7 @@ #include #include "Exceptions.h" #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -112,9 +113,9 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset; string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; - string const c_space = c_border + string(76, ' ') + c_border; + string const c_space = c_border + string(76, ' ') + c_border + EthReset; stringstream ss; ss << c_line << endl; ss << c_space << endl; diff --git a/libethcore/Common.h b/libethcore/Common.h index 296f0d01d..1e0cdc3b1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -189,6 +189,7 @@ struct TransactionSkeleton Address to; u256 value; bytes data; + u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; u256 nonce = UndefinedU256; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9be76926d..6a4a1445f 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -46,6 +46,7 @@ #endif #include "BlockInfo.h" #include "EthashAux.h" +#include "Exceptions.h" using namespace std; using namespace std::chrono; @@ -56,6 +57,26 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); +void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +{ + if (!io_out) + io_out = EthashAux::seedHash((unsigned)_h.number); +} + +void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); + _ex << errinfo_mixHash(_bi.proof.mixHash); + _ex << errinfo_seedHash(_bi.proofCache()); + Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); + _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +} + +void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); +} + std::string Ethash::name() { return "Ethash"; @@ -66,12 +87,23 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) +{ + mixHash = _header[_field].toHash(RLP::VeryStrict); + nonce = _header[++_field].toHash(RLP::VeryStrict); +} + +void Ethash::Solution::streamRLP(RLPStream& io_rlp) const +{ + io_rlp << mixHash << nonce; +} + Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutNonce); - ret.seedHash = _bi.seedHash(); + ret.headerHash = _bi.headerHash(WithoutProof); + ret.seedHash = _bi.proofCache(); return ret; } @@ -84,7 +116,7 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { - EthashAux::full(_header.seedHash(), true, _f); + EthashAux::full(_header.proofCache(), true, _f); } bool Ethash::preVerify(BlockInfo const& _header) @@ -95,9 +127,9 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), + (uint64_t)(u64)_header.proof.nonce, + (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); return ret; @@ -115,7 +147,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -125,9 +157,9 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; + cwarn << "headerHash:" << _header.headerHash(WithoutProof); + cwarn << "nonce:" << _header.proof.nonce; + cwarn << "mixHash:" << _header.proof.mixHash; cwarn << "difficulty:" << _header.difficulty; cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 7ffd887d0..5640152f0 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -28,16 +28,20 @@ #include #include #include "Common.h" -#include "BlockInfo.h" #include "Miner.h" class ethash_cl_miner; namespace dev { + +class RLP; +class RLPStream; + namespace eth { +class BlockInfo; class EthashCLHook; class Ethash @@ -45,8 +49,17 @@ class Ethash public: using Miner = GenericMiner; + using HeaderCache = h256; + static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); + static void composeException(Exception& _ex, BlockInfo& _bi); + static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + struct Solution { + bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } + void populateFromRLP(RLP const& io_rlp, int& io_field); + void streamRLP(RLPStream& io_rlp) const; + static const unsigned Fields = 2; Nonce nonce; h256 mixHash; }; @@ -78,7 +91,6 @@ public: static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } class CPUMiner: public Miner, Worker { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index efb6066f7..db01f3c49 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,6 +200,11 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } +Ethash::Result EthashAux::eval(BlockInfo const& _header) +{ + return eval(_header, _header.proof.nonce); +} + #define DEV_IF_THROWS(X) try { X; } catch (...) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) @@ -252,7 +257,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { - return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); + return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index d5bd60d44..be07f579c 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -78,7 +78,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 764207aef..7b4298047 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -38,7 +38,6 @@ namespace eth * typename Solution * typename CPUMiner * typename GPUMiner - * void assignResult(BlockInfo&, Result) * and a few others. TODO */ using ProofOfWork = Ethash; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 768ed223f..aaafe7ce9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -575,8 +575,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash.abridged() @@ -666,8 +666,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f95a3880e..690fb60ee 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.hash; + bi.proof.mixHash = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.mixHash == work.hash) + if (it->verified.info.proof.mixHash == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.mixHash == work.hash) + if (i.verified.info.proof.mixHash == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..bf55a50ff 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -837,7 +837,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); + m_currentBlock.streamRLP(block, WithProof); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -902,7 +902,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithNonce); + ubi.streamRLP(unclesData, WithProof); ++unclesCount; uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) @@ -970,7 +970,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithNonce); + m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -978,7 +978,7 @@ void State::completeMine() cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.nonce.abridged(), + m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() ); diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..0555b6dcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -169,11 +169,11 @@ public: if (!m_committedToMine) return false; - PoW::assignResult(_result, m_currentBlock); + m_currentBlock.proof = _result; if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..f7c09ebc2 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -99,11 +99,12 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["gasLimit"] = toJS(_bi.gasLimit); res["timestamp"] = toJS(_bi.timestamp); res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); res["logsBloom"] = toJS(_bi.logBloom); - - res["seedHash"] = toJS(_bi.seedHash()); res["target"] = toJS(_bi.boundary()); + + // TODO: move into ProofOfWork. + res["nonce"] = toJS(_bi.proof.nonce); + res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 8373c7c51..ea4686601 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -49,7 +49,6 @@ namespace struct MixPow //dummy POW { typedef int Solution; - static void assignResult(int, BlockInfo const&) {} static bool verify(BlockInfo const&) { return true; } }; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f49ed1e09..b43c4db51 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(BlockInfo& _bi) bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, _bi); + _bi.proof = sol; return completed = true; }); f.setWork(_bi); From 88cd4dfad7d64018441d6e80d47c111c1dcd8da4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 13:03:52 -0700 Subject: [PATCH 050/113] Basic Proof-of-Authority sealent. --- eth/main.cpp | 3 + ethminer/MinerAux.h | 28 +++++++-- libdevcrypto/Common.cpp | 5 ++ libdevcrypto/Common.h | 3 + libethcore/Common.cpp | 4 ++ libethcore/Common.h | 13 +++- libethcore/Ethash.cpp | 26 +++++++- libethcore/Ethash.h | 31 +++++++++ libethcore/EthashAux.cpp | 11 ++++ libethcore/EthashAux.h | 1 + libethcore/Farm.h | 1 - libethcore/Miner.h | 11 ---- libethcore/ProofOfWork.cpp | 25 ++++++++ libethcore/ProofOfWork.h | 76 ++++++++++++++++++++++- libethereum/BlockChain.cpp | 4 ++ libethereum/BlockQueue.cpp | 12 ++-- libethereum/Client.cpp | 15 +---- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 +- libethereum/State.h | 2 +- libweb3jsonrpc/JsonHelper.cpp | 2 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 10 ++- 22 files changed, 246 insertions(+), 43 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 5b38f2779..434860f59 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1700,7 +1700,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) { From 02557813a98f3d89cd7a08c51560ad52679517a6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH 051/113] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + 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 BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + 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 BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - 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); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) 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)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); - _ex << errinfo_mixHash(_bi.proof.mixHash); - _ex << errinfo_seedHash(_bi.proofCache()); - Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); - _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); -#else - (void)_ex; - (void)_bi; -#endif -} - -void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) -{ -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); -#else - (void)_ex; - (void)_bi; -#endif -} - -std::string Ethash::name() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) -{ - WorkPackage ret; - ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutProof); -#if ETH_USING_ETHASH - ret.seedHash = _bi.proofCache(); -#endif - return ret; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -void Ethash::prep(BlockInfo const& _header, std::function const& _f) -{ -#if ETH_USING_ETHASH - EthashAux::full(_header.proofCache(), true, _f); -#else - (void)_header; - (void)_f; -#endif + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (number >= ETHASH_EPOCH_LENGTH * 2048) return false; -#if ETH_USING_ETHASH - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ bool Ethash::verify(BlockInfo const& _header) } #endif -#if ETH_USING_ETHASH - auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + 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, unsigned, 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 + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - 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, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#else - using GPUMiner = CPUMiner; -#endif /// Default value of the local work size. Also known as workgroup size. static const unsigned defaultLocalWorkSize; /// Default value of the global work size as a multiplier of the local work size static const unsigned defaultGlobalWorkSizeMultiplier; /// Default value of the milliseconds per global work size (per batch) static const unsigned defaultMSPerBatch; - - struct Farm: public eth::GenericFarm - { - public: - strings sealers() const { return { "cpu", "opencl" }; } - void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } - - void sealBlock(BlockInfo const& _bi) - { - setWork(_bi); - if (m_opencl) - startGPU(); - else - startCPU(); - - setWork(_bi); - ensurePrecomputed((unsigned)_bi.number); - } - - void disable() { stop(); } - - private: - bool m_opencl = false; - }; }; } diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) - return true; - m_miners.clear(); - m_miners.reserve(MinerType::instances()); - for (unsigned i = 0; i < MinerType::instances(); ++i) - { - m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); - -bool BasicAuthority::verify(BlockInfo const& _header) -{ - return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; -} - -bool BasicAuthority::preVerify(BlockInfo const& _header) -{ - return SignatureStruct(_header.proof.sig).isValid(); -} - -BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) -{ - return WorkPackage{_header.headerHash(WithoutProof)}; -} - -void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) -{ - m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); -} - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -class BasicAuthority -{ -public: - struct HeaderCache {}; - static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} - static void composeException(Exception&, BlockInfo&) {} - static void composeExceptionPre(Exception&, BlockInfo&) {} - - struct Solution - { - bool operator==(Solution const& _v) const { return sig == _v.sig; } - void populateFromRLP(RLP const& io_rlp, int& io_field) - { - sig = io_rlp[io_field++].toHash(RLP::VeryStrict); - } - - void streamRLP(RLPStream& io_rlp) const - { - io_rlp << sig; - } - static const unsigned Fields = 1; - Signature sig; - }; - - struct Result - { - Signature sig; - }; - - struct WorkPackage - { - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } - - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - }; - - static const WorkPackage NullWorkPackage; - - static std::string name() { return "BasicAuthority"; } - static unsigned revision() { return 0; } - static void prep(BlockInfo const&, std::function const& = std::function()) {} - static void ensurePrecomputed(unsigned) {} - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - static const Address Authority; - - struct Farm - { - public: - strings sealers() const { return { "default" }; } - void setSealer(std::string const&) {} - void setSecret(Secret const& _s) { m_secret = _s; } - void sealBlock(BlockInfo const& _bi); - void disable() {} - void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } - - private: - Secret m_secret; - std::function m_onSolutionFound; - }; -}; - using ProofOfWork = BasicAuthority; } diff --git a/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + 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 Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + 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 Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady; From 57e1ae26f70eb7f187fbee7fab8ba94aa99f3267 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Jul 2015 16:32:04 -0700 Subject: [PATCH 052/113] Tests working for BasicAuthority and Ethash. --- CMakeLists.txt | 32 ++++++++++++++-------------- exp/CMakeLists.txt | 20 ++++++++++++------ exp/main.cpp | 40 ++++++++++++++++++++++++++--------- libdevcore/Common.h | 1 + libethcore/BasicAuthority.cpp | 18 +++++++++++++--- libethcore/BasicAuthority.h | 7 +++++- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 1 + libethcore/EthashAux.cpp | 23 -------------------- libethcore/EthashAux.h | 2 -- libethcore/Sealer.h | 12 +++++++++++ 12 files changed, 97 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b926ae165..2ac467fbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) - add_subdirectory(libweb3jsonrpc) +# add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) - add_subdirectory(libjsengine) - add_subdirectory(libjsconsole) - add_subdirectory(ethconsole) +# add_subdirectory(libjsengine) +# add_subdirectory(libjsconsole) +# add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -432,33 +432,33 @@ endif () add_subdirectory(libethcore) if (GENERAL) - add_subdirectory(libevm) - add_subdirectory(libethereum) - add_subdirectory(libwebthree) +# add_subdirectory(libevm) +# add_subdirectory(libethereum) +# add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) - add_subdirectory(ethminer) +# add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) - add_subdirectory(ethkey) +# add_subdirectory(ethkey) endif () if (TESTS) - add_subdirectory(libtestutils) - add_subdirectory(test) +# add_subdirectory(libtestutils) +# add_subdirectory(test) if (JSONRPC) - add_subdirectory(ethrpctest) +# add_subdirectory(ethrpctest) endif () endif () if (TOOLS) - add_subdirectory(rlp) - add_subdirectory(abi) - add_subdirectory(ethvm) - add_subdirectory(eth) +# add_subdirectory(rlp) +# add_subdirectory(abi) +# add_subdirectory(ethvm) +# add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 7a80023bf..30f4705f9 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,15 +18,21 @@ if (READLINE_FOUND) endif() if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) +# target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} p2p) +#target_link_libraries(${EXECUTABLE} webthree) +#target_link_libraries(${EXECUTABLE} ethereum) +#target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} ethash) - target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} ethash-cl) +# target_link_libraries(${EXECUTABLE} ethash) +# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) endif() +target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) + + + + + diff --git a/exp/main.cpp b/exp/main.cpp index 07eee6a11..fa8603459 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,6 +70,7 @@ namespace fs = boost::filesystem; #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -80,24 +81,43 @@ using namespace eth; int main() { BlockInfo bi; + bi.difficulty = c_genesisDifficulty; + bi.gasLimit = c_genesisGasLimit; + bi.number = 1; + bi.parentHash = sha3("parentHash"); + bytes sealedData; - SealEngineFace* se = BasicAuthority::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); - se->generateSeal(bi); { + KeyPair kp(sha3("test")); + SealEngineFace* se = BasicAuthority::createSealEngine(); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); + cdebug << se->sealers(); + bool done = false; + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.sig(); } - SealEngineFace* se = Ethash::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); - se->generateSeal(bi); - while (!done) - this_thread::sleep_for(chrono::milliseconds(50)); { + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + bool done = false; + se->setSealer("cpu"); + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.nonce(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 303512e57..612b7c685 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using byte = uint8_t; #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) namespace dev { diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index bbf4e3f2a..7006107e1 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); +AddressHash BasicAuthority::s_authorities; bool BasicAuthority::BlockHeaderRaw::verify() const { - return toAddress(recover(m_sig, hashWithout())) == Authority; + return s_authorities.count(toAddress(recover(m_sig, hashWithout()))); } bool BasicAuthority::BlockHeaderRaw::preVerify() const @@ -94,11 +94,23 @@ public: MiningProgress miningProgress() const { return MiningProgress(); } private: + virtual bool onOptionChanging(std::string const& _name, bytes const& _value) + { + RLP rlp(_value); + if (_name == "authorities") + BasicAuthority::s_authorities = rlp.toUnorderedSet
(); + else if (_name == "authority") + m_secret = rlp.toHash(); + else + return false; + return true; + } + Secret m_secret; std::function m_onSealGenerated; }; -SealEngineFace* createSealEngine() +SealEngineFace* BasicAuthority::createSealEngine() { return new BasicAuthoritySealEngine; } diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 616c18340..9127c1d53 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -30,6 +30,7 @@ #include "Sealer.h" class BasicAuthoritySeal; +class BasicAuthoritySealEngine; namespace dev { @@ -48,6 +49,8 @@ namespace eth */ class BasicAuthority { + friend class ::BasicAuthoritySealEngine; + public: // TODO: remove struct Result {}; @@ -70,6 +73,7 @@ public: Signature sig() const { return m_sig; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 1; @@ -84,7 +88,8 @@ public: }; using BlockHeader = BlockHeaderPolished; - static const Address Authority; +private: + static AddressHash s_authorities; }; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index cd55bc1f6..710279cb2 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -158,7 +158,7 @@ public: explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c3f19e723..d385163be 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -119,7 +119,7 @@ bool Ethash::BlockHeaderRaw::verify() const } #endif - auto result = EthashAux::eval(*this); + auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce); bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); @@ -281,6 +281,7 @@ public: { m_farm.onSolutionFound([=](Ethash::Solution const& sol) { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; EthashSeal s(sol.mixHash, sol.nonce); _f(&s); return true; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index eee0e3881..99baa8a05 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -94,6 +94,7 @@ public: h256 const& mixHash() const { return m_mixHash; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 2; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 42a3cf6fb..00537c21a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,18 +200,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } -Ethash::Result EthashAux::eval(BlockInfo const& _header) -{ -#if ETH_USING_ETHASH - return eval(_header, _header.proof.nonce); -#else - (void)_header; - return Ethash::Result(); -#endif -} - -#define DEV_IF_THROWS(X) try { X; } catch (...) - unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); @@ -260,17 +248,6 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) -{ -#if ETH_USING_ETHASH - return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); -#else - (void)_header; - (void)_nonce; - return Ethash::Result(); -#endif -} - Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 5ae24898d..132b9b436 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -79,8 +79,6 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header); - static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index f491240f3..28381444e 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include "Common.h" namespace dev @@ -43,6 +44,9 @@ public: class SealEngineFace { public: + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; @@ -52,6 +56,14 @@ public: // TODO: rename & generalise virtual bool isMining() const { return false; } virtual MiningProgress miningProgress() const { return MiningProgress(); } + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; }; } From e18e3de824a0e5b94974b589c014ea1bbffebfa5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jul 2015 23:24:10 +0200 Subject: [PATCH 053/113] Basic test working with same code for Ethash and BasicAuthority. --- CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 1 - ethminer/MinerAux.h | 17 +-- exp/CMakeLists.txt | 6 +- exp/main.cpp | 86 +++++++------ libdevcore/Guards.h | 29 +++++ libdevcore/RLP.h | 3 + libdevcore/TrieDB.h | 9 +- libethcore/BasicAuthority.cpp | 43 ++++--- libethcore/BasicAuthority.h | 16 +-- libethcore/BlockInfo.cpp | 34 +---- libethcore/BlockInfo.h | 64 ++++++--- libethcore/Common.cpp | 3 +- libethcore/Common.h | 14 +- libethcore/Ethash.cpp | 163 ++++++++++++----------- libethcore/Ethash.h | 52 ++------ libethcore/EthashAux.cpp | 17 ++- libethcore/EthashAux.h | 47 ++++++- libethcore/Farm.h | 6 +- libethcore/Miner.h | 4 +- libethcore/ProofOfWork.cpp | 27 ---- libethcore/ProofOfWork.h | 40 ------ libethcore/Sealer.h | 31 +++-- libethereum/BlockChain.cpp | 136 ++++++++++---------- libethereum/BlockChain.h | 113 ++++++++++++++-- libethereum/BlockChainSync.cpp | 11 +- libethereum/BlockQueue.cpp | 24 ++-- libethereum/BlockQueue.h | 8 +- libethereum/CanonBlockChain.cpp | 75 ++++++----- libethereum/CanonBlockChain.h | 45 ++++++- libethereum/Client.cpp | 200 ++++++++++++++++------------- libethereum/Client.h | 119 +++++++++++------ libethereum/ClientBase.cpp | 2 +- libethereum/ClientBase.h | 4 +- libethereum/Interface.h | 8 +- libethereum/State.cpp | 87 ++++++------- libethereum/State.h | 66 ++++------ libethereum/Utility.cpp | 4 +- libethereum/Utility.h | 3 +- libweb3jsonrpc/JsonHelper.cpp | 6 +- libweb3jsonrpc/JsonHelper.h | 14 ++ test/libethcore/dagger.cpp | 3 +- test/libethereum/stateOriginal.cpp | 3 +- 44 files changed, 933 insertions(+), 716 deletions(-) delete mode 100644 libethcore/ProofOfWork.cpp delete mode 100644 libethcore/ProofOfWork.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ac467fbd..3efc5bad9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,8 +432,8 @@ endif () add_subdirectory(libethcore) if (GENERAL) -# add_subdirectory(libevm) -# add_subdirectory(libethereum) + add_subdirectory(libevm) + add_subdirectory(libethereum) # add_subdirectory(libwebthree) endif () diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4655240e3..2ee8928f5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -208,7 +208,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); diff --git a/eth/main.cpp b/eth/main.cpp index 434860f59..7ce4d49c2 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 051128669..61fde605d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #if ETH_ETHASHCL || !ETH_TRUE @@ -387,7 +386,6 @@ public: #endif } -#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -412,10 +410,10 @@ private: genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - GenericFarm f; - f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + GenericFarm f; + f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); - string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; @@ -488,20 +486,20 @@ private: jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; + GenericFarm f; if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) f.startGPU(); - ProofOfWork::WorkPackage current; + EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; while (true) try { bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) + EthashProofOfWork::Solution solution; + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { solution = sol; return completed = true; @@ -595,5 +593,4 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; -#endif }; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 30f4705f9..5f876a69b 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -22,12 +22,12 @@ if (JSONRPC) endif() #target_link_libraries(${EXECUTABLE} webthree) -#target_link_libraries(${EXECUTABLE} ethereum) -#target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) # target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash) -# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} OpenCL) endif() target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/exp/main.cpp b/exp/main.cpp index fa8603459..4a35068f1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -71,13 +70,16 @@ namespace fs = boost::filesystem; #include #include #include +#include +#include +#include +#include using namespace std; using namespace dev; using namespace eth; #endif -#if 1 - +#if 0 int main() { BlockInfo bi; @@ -124,9 +126,7 @@ int main() return 0; } - #elif 0 - int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); @@ -135,10 +135,7 @@ int main() cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); return 0; } - - #elif 0 - int main() { cdebug << "EXP"; @@ -162,9 +159,7 @@ int main() ret = orderedTrieRoot(data); cdebug << ret; } - #elif 0 - int main() { KeyManager keyman; @@ -186,7 +181,6 @@ int main() cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); } - #elif 0 int main() { @@ -246,15 +240,15 @@ int main() #elif 0 int main() { - GenericFarm f; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { BlockInfo bi = g; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { bi.proof = sol; return completed = true; @@ -289,23 +283,16 @@ int main() return 0; } -#elif 0 - -void mine(State& s, BlockChain const& _bc) +#elif 1 +void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) { s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - return completed = s.completeMine(sol); - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + _se->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); } -#elif 0 int main() { cnote << "Testing State..."; @@ -316,47 +303,62 @@ int main() Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; - cout << bc; + using Sealer = Ethash; + CanonBlockChain bc; + auto gbb = bc.headerData(bc.genesisHash()); + assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData)); + + SealEngineFace* se = Sealer::createSealEngine(); + KeyPair kp(sha3("test")); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); - cout << s; + OverlayDB stateDB = State::openDB(bc.genesisHash()); + cnote << bc; + + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); + cnote << s; // Sync up - this won't do much until we use the last state. s.sync(bc); - cout << s; + cnote << s; // Mine to get some ether! - mine(s, bc); + mine(s, bc, se); - bc.attemptImport(s.blockData(), stateDB); + bytes minedBlock = s.blockData(); + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + bc.import(minedBlock, stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; + cnote << "Miner now has" << s.balance(myMiner.address()); + s.resetCurrent(); + cnote << "Miner now has" << s.balance(myMiner.address()); // Inject a transaction to transfer funds from miner to me. Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); - cout << s; + cnote << s; // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - mine(s, bc); + mine(s, bc, se); bc.attemptImport(s.blockData(), stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; return 0; } diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 44d5969e4..135209d23 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex; using SharedMutex = boost::shared_mutex; using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; using RecursiveGuard = std::lock_guard; using ReadGuard = boost::shared_lock; using UpgradableGuard = boost::upgrade_lock; @@ -74,6 +76,33 @@ private: }; using SpinGuard = std::lock_guard; +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a94c8ba55..701f4b8e8 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -393,6 +393,9 @@ public: /// Read the byte stream. bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + /// Swap the contents of the output stream out for some other byte array. void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..05affa677 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -231,8 +231,11 @@ public: } } -protected: - DB* db() const { return m_db; } + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -383,6 +386,7 @@ public: using Super::isEmpty; using Super::root; + using Super::db; using Super::leftOvers; using Super::check; @@ -435,6 +439,7 @@ public: using Super::check; using Super::open; using Super::setRoot; + using Super::db; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7006107e1..22da67080 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -19,6 +19,7 @@ * @date 2014 */ +#include #include "Exceptions.h" #include "BasicAuthority.h" #include "BlockInfo.h" @@ -60,38 +61,38 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri } } +void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} +void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} -class BasicAuthoritySeal: public SealFace +StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const { -public: - BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + return { { "sig", toJS(m_sig) } }; +} - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - BasicAuthority::BlockHeader h(_bi); - h.m_sig = m_sig; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } -private: - Signature m_sig; -}; -class BasicAuthoritySealEngine: public SealEngineFace +class BasicAuthoritySealEngine: public SealEngineBase { public: void setSecret(Secret const& _s) { m_secret = _s; } void generateSeal(BlockInfo const& _bi) { - BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); - m_onSealGenerated(&s); + BasicAuthority::BlockHeader h(_bi); + h.m_sig = sign(m_secret, _bi.hashWithout()); + RLPStream ret; + h.streamRLP(ret); + m_onSealGenerated(ret.out()); } - void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isWorking() const { return false; } + WorkingProgress workingProgress() const { return WorkingProgress(); } private: virtual bool onOptionChanging(std::string const& _name, bytes const& _value) @@ -107,7 +108,7 @@ private: } Secret m_secret; - std::function m_onSealGenerated; + std::function m_onSealGenerated; }; SealEngineFace* BasicAuthority::createSealEngine() diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 9127c1d53..8db47938b 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -52,33 +52,31 @@ class BasicAuthority friend class ::BasicAuthoritySealEngine; public: - // TODO: remove - struct Result {}; - struct WorkPackage {}; - static const WorkPackage NullWorkPackage; - static std::string name() { return "BasicAuthority"; } static unsigned revision() { return 0; } static SealEngineFace* createSealEngine(); class BlockHeaderRaw: public BlockInfo { - friend class ::BasicAuthoritySeal; + friend class ::BasicAuthoritySealEngine; public: + static const unsigned SealFields = 1; + bool verify() const; bool preVerify() const; - WorkPackage package() const { return NullWorkPackage; } Signature sig() const { return m_sig; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 1; - void populateFromHeader(RLP const& _header, Strictness _s); + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); void streamRLPFields(RLPStream& _s) const { _s << m_sig; } void clear() { m_sig = Signature(); } void noteDirty() const {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb07162fb..64961bc40 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,10 +36,10 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt) { - RLP header = extractHeader(_block); - m_hash = sha3(header.data()); + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); populateFromHeader(header, _s); } @@ -58,7 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - m_hashWithout = h256(); + noteDirty(); } h256 const& BlockInfo::boundary() const @@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing) - { - if (gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); - - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); - - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); - - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); - } + if (_s != CheckNothing && gasUsed > gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) gasLimit = selectGasLimit(_parent); gasUsed = 0; difficulty = calculateDifficulty(_parent); + parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const @@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const void BlockInfo::verifyParent(BlockInfo const& _parent) const { - // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); - - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); - // Check timestamp is after previous timestamp. if (parentHash) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 710279cb2..b00fa73fb 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -42,10 +42,18 @@ enum Strictness { CheckEverything, QuickNonce, - IgnoreNonce, + IgnoreSeal, CheckNothing }; +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); + /** @brief Encapsulation of a block header. * Class to contain all of a block header's data. It is able to parse a block header and populate * from some given RLP block serialisation with the static fromHeader(), through the method @@ -69,7 +77,10 @@ enum Strictness */ struct BlockInfo { + friend class BlockChain; public: + static const unsigned BasicFields = 13; + // TODO: make them all private! h256 parentHash; h256 sha3Uncles; @@ -78,7 +89,7 @@ public: h256 transactionsRoot; h256 receiptsRoot; LogBloom logBloom; - u256 difficulty; + u256 difficulty; // TODO: pull out into BlockHeader u256 number; u256 gasLimit; u256 gasUsed; @@ -86,10 +97,12 @@ public: bytes extraData; BlockInfo(); - BlockInfo(bytesConstRef _block, Strictness _s); + explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); + explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -121,17 +134,14 @@ public: /// sha3 of the header only. h256 const& hashWithout() const; - h256 const& hash() const { return m_hash; } - -protected: - static RLP extractHeader(bytesConstRef _block); - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); - void streamRLPFields(RLPStream& _s) const; + h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } void clear(); void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } - static const unsigned BasicFields = 13; +protected: + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal); + void streamRLPFields(RLPStream& _s) const; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. @@ -152,35 +162,50 @@ template class BlockHeaderPolished: public BlockInfoSub { public: + static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields; + BlockHeaderPolished() {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} - explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } - explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); } + explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); } - static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } + // deprecated - just use constructor instead. + static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } + static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } - void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + // deprecated for public API - use constructor. + // TODO: make private. + void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData) + { + populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h); + } void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); BlockInfo::parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); + BlockInfoSub::populateFromParent(_parent); } + // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); + BlockInfoSub::verifyParent(_parent); } - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + // deprecated for public API - use constructor. + // TODO: make private. + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { BlockInfo::m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); + else + BlockInfo::m_hash = dev::sha3(_header.data()); if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); @@ -213,6 +238,13 @@ public: if (_i == WithProof) BlockInfoSub::streamRLPFields(_s); } + + bytes sealFieldsRLP() const + { + RLPStream s; + BlockInfoSub::streamRLPFields(s); + return s.out(); + } }; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 58e506b37..499854584 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -29,7 +29,6 @@ #include #include #include "Exceptions.h" -#include "ProofOfWork.h" #include "BlockInfo.h" using namespace std; using namespace dev; @@ -57,7 +56,7 @@ Network const c_network = Network::Frontier; Network const c_network = Network::Olympic; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 1a688fbd8..5c0a0cc79 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -124,10 +124,16 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, ///< Validate nonce + ValidSeal = 1, ///< Validate seal DontHave = 2, ///< Avoid old blocks - CheckUncles = 4, ///< Check uncle nonces - Default = ValidNonce | DontHave | CheckUncles + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures + Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + None = 0 }; }; @@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(& /** * @brief Describes the progress of a mining operation. */ -struct MiningProgress +struct WorkingProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index d385163be..128822b80 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "Exceptions.h" #include "Farm.h" #include "Miner.h" +#include "Params.h" using namespace std; using namespace std::chrono; @@ -57,8 +59,6 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); - h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) @@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); ex << errinfo_mixHash(m_mixHash); ex << errinfo_seedHash(seedHash()); - Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); ex << errinfo_difficulty(difficulty); @@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } + + if (_s != CheckNothing) + { + if (difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + + if (gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + + if (number && extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + } +} + +void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + + if (gasLimit < c_minGasLimit || + gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || + gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); +} + +void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; } bool Ethash::BlockHeaderRaw::preVerify() const @@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const return slow; } -Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const -{ - WorkPackage ret; - ret.boundary = boundary(); - ret.headerHash = hashWithout(); - ret.seedHash = seedHash(); - return ret; -} - void Ethash::BlockHeaderRaw::prep(std::function const& _f) const { EthashAux::full(seedHash(), true, _f); } +StringHashMap Ethash::BlockHeaderRaw::jsInfo() const +{ + return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; +} @@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function const& _f) const -class EthashCPUMiner: public GenericMiner, Worker +class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -190,7 +214,7 @@ private: }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker +class EthashGPUMiner: public GenericMiner, Worker { friend class dev::eth::EthashCLHook; @@ -234,66 +258,84 @@ private: }; #endif -class EthashSeal: public SealFace +struct EthashSealEngine: public SealEngineBase { -public: - EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} - - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - Ethash::BlockHeader h(_bi); - h.m_mixHash = m_mixHash; - h.m_nonce = m_nonce; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } - -private: - h256 m_mixHash; - h64 m_nonce; -}; + friend class Ethash; -struct EthashSealEngine: public SealEngineFace -{ public: EthashSealEngine() { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; #if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; #endif m_farm.setSealers(sealers); } - strings sealers() const override { return { "cpu", "opencl" }; } + strings sealers() const override + { + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; + } void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void disable() override { m_farm.stop(); } + void cancelGeneration() override { m_farm.stop(); } void generateSeal(BlockInfo const& _bi) override { - m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); m_farm.start(m_sealer); - m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + m_farm.setWork(m_sealing); // TODO: take out one before or one after... Ethash::ensurePrecomputed((unsigned)_bi.number); } - void onSealGenerated(std::function const& _f) override + void onSealGenerated(std::function const& _f) override { - m_farm.onSolutionFound([=](Ethash::Solution const& sol) + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) { cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - EthashSeal s(sol.mixHash, sol.nonce); - _f(&s); + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); return true; }); } private: bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; }; +void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + // Go via the farm since the handler function object is stored as a local within the Farm's lambda. + // Has the side effect of stopping local workers, which is good, as long as it only does it for + // valid submissions. + static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); +} + +bool Ethash::isWorking(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.isMining(); + return false; +} + +WorkingProgress Ethash::workingProgress(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.miningProgress(); + return WorkingProgress(); +} + SealEngineFace* Ethash::createSealEngine() { return new EthashSealEngine; @@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE -using UniqueGuard = std::unique_lock; - -template -class Notified -{ -public: - Notified() {} - Notified(N const& _v): m_value(_v) {} - Notified(Notified const&) = delete; - Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - - operator N() const { UniqueGuard l(m_mutex); return m_value; } - - void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } - -private: - mutable Mutex m_mutex; - mutable std::condition_variable m_cv; - N m_value; -}; - class EthashCLHook: public ethash_cl_miner::search_hook { public: diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99baa8a05..576621bd4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -53,59 +53,42 @@ public: static unsigned revision(); static SealEngineFace* createSealEngine(); - // TODO: remove or virtualize - struct Solution - { - h64 nonce; - h256 mixHash; - }; - // TODO: make private - struct Result - { - h256 value; - h256 mixHash; - }; - // TODO: virtualise - struct WorkPackage - { - WorkPackage() = default; - - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } + using Nonce = h64; - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; - }; - static const WorkPackage NullWorkPackage; + static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce); + static bool isWorking(SealEngineFace* _engine); + static WorkingProgress workingProgress(SealEngineFace* _engine); class BlockHeaderRaw: public BlockInfo { - friend class EthashSeal; + friend class EthashSealEngine; public: + static const unsigned SealFields = 2; + bool verify() const; bool preVerify() const; void prep(std::function const& _f = std::function()) const; - WorkPackage package() const; h256 const& seedHash() const; - h64 const& nonce() const { return m_nonce; } + Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 2; - void populateFromHeader(RLP const& _header, Strictness _s); - void clear() { m_mixHash = h256(); m_nonce = h64(); } + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); + void clear() { m_mixHash = h256(); m_nonce = Nonce(); } void noteDirty() const { m_seedHash = h256(); } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - h64 m_nonce; + Nonce m_nonce; h256 m_mixHash; mutable h256 m_seedHash; @@ -115,13 +98,6 @@ public: // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); - - /// Default value of the local work size. Also known as workgroup size. - static const unsigned defaultLocalWorkSize; - /// Default value of the global work size as a multiplier of the local work size - static const unsigned defaultGlobalWorkSizeMultiplier; - /// Default value of the milliseconds per global work size (per batch) - static const unsigned defaultMSPerBatch; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 00537c21a..c511978db 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; } EthashAux* dev::eth::EthashAux::s_this = nullptr; +const unsigned EthashProofOfWork::defaultLocalWorkSize = 64; +const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE +const unsigned EthashProofOfWork::defaultMSPerBatch = 0; +const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage(); + EthashAux::~EthashAux() { } @@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; } -Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) if (FullType dag = get()->m_fulls[_seedHash].lock()) return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { - return Ethash::Result{ ~h256(), h256() }; + return EthashProofOfWork::Result{ ~h256(), h256() }; } } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 132b9b436..d42e46d91 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -34,6 +34,47 @@ namespace eth struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; +/// Proof of work definition for Ethash. +struct EthashProofOfWork +{ + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + WorkPackage() = default; + WorkPackage(Ethash::BlockHeader const& _bh): + boundary(_bh.boundary()), + headerHash(_bh.hashWithout()), + seedHash(_bh.seedHash()) + {} + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; +}; + class EthashAux { public: @@ -46,7 +87,7 @@ public: LightAllocation(h256 const& _seedHash); ~LightAllocation(); bytesConstRef data() const; - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; ethash_light_t light; uint64_t size; }; @@ -55,7 +96,7 @@ public: { FullAllocation(ethash_light_t _light, ethash_callback_t _cb); ~FullAllocation(); - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; bytesConstRef data() const; uint64_t size() const { return ethash_full_dag_size(full); } ethash_full_t full; @@ -79,7 +120,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: EthashAux() {} diff --git a/libethcore/Farm.h b/libethcore/Farm.h index b69f8325a..c86b4804e 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -123,9 +123,9 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const + WorkingProgress const& miningProgress() const { - MiningProgress p; + WorkingProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); @@ -195,7 +195,7 @@ private: std::atomic m_isMining = {false}; mutable SharedMutex x_progress; - mutable MiningProgress m_progress; + mutable WorkingProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 03eba9880..90a5902c4 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,9 +36,9 @@ namespace dev namespace eth { -struct MineInfo: public MiningProgress {}; +struct MineInfo: public WorkingProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) +inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p) { _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp deleted file mode 100644 index 843db72c7..000000000 --- a/libethcore/ProofOfWork.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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 ProofOfWork.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "ProofOfWork.h" -#include "BlockInfo.h" -using namespace std; -using namespace dev; -using namespace eth; - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h deleted file mode 100644 index f55c54df6..000000000 --- a/libethcore/ProofOfWork.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 ProofOfWork.h - * @author Gav Wood - * @date 2014 - * - * Determines the PoW algorithm. - */ - -#pragma once - -#include -#include -#include "Common.h" -//#include "Ethash.h" -#include "BasicAuthority.h" - -namespace dev -{ -namespace eth -{ - -using ProofOfWork = BasicAuthority; - -} -} diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index 28381444e..137659dfc 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -25,6 +25,7 @@ #include #include +#include #include "Common.h" namespace dev @@ -34,28 +35,22 @@ namespace eth class BlockInfo; -class SealFace -{ -public: - virtual bool wouldSealHeader(BlockInfo const&) const { return true; } - virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; -}; - class SealEngineFace { public: + virtual std::string name() const = 0; + virtual unsigned revision() const = 0; + virtual unsigned sealFields() const = 0; + virtual bytes sealRLP() const = 0; + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; - virtual void onSealGenerated(std::function const& _f) = 0; - virtual void disable() {} - - // TODO: rename & generalise - virtual bool isMining() const { return false; } - virtual MiningProgress miningProgress() const { return MiningProgress(); } + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} protected: virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } @@ -66,5 +61,15 @@ private: std::unordered_map m_options; }; +template +class SealEngineBase: public SealEngineFace +{ +public: + std::string name() const override { return Sealer::name(); } + unsigned revision() const override { return Sealer::revision(); } + unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; } + bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); } +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 14b13b90d..aae8cbd10 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,12 +35,12 @@ #include #include #include -#include #include #include #include #include "GenesisInfo.h" #include "State.h" +#include "Utility.h" #include "Defaults.h" using namespace std; @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 1 +#define ETH_CATCH 0 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 @@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): + m_genesisState(_genesisState) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit // Initialise with the genesis as the last block on the longest chain. m_genesisBlock = _genesisBlock; m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); + m_genesisState = _genesisState; + + // remove the next line real soon. we don't need to be supporting this forever. + upgradeDatabase(_path, genesisHash()); if (open(_path, _we) != c_minorProtocolVersion) rebuild(_path, _p); @@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); - BlockInfo bi(b); + BlockInfo bi(&b); if (_prepPoW) - Ethash::prep(bi); + Ethash::ensurePrecomputed((unsigned)bi.number); if (bi.parentHash != lastHash) { @@ -351,7 +356,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; @@ -388,7 +393,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad, _ir); + block = verifyBlock(&_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) @@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& auto parentBlock = block(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; - clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); + clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); @@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(_block, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this); for (unsigned i = 0; i < s.pending().size(); ++i) { @@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db) try { cout << "block..." << flush; - BlockInfo bi = info(h); - cout << "details..." << flush; - BlockDetails bd = details(h); + BlockInfo bi(block(h)); + cout << "extras..." << flush; + details(h); cout << "state..." << flush; if (_db.exists(bi.stateRoot)) break; @@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +bytes BlockChain::headerData(h256 const& _hash) const { - VerifiedBlockRef res; - try - { - Strictness strictness = Strictness::CheckEverything; - if (~_ir & ImportRequirements::ValidNonce) - strictness = Strictness::IgnoreNonce; + if (_hash == m_genesisHash) + return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes(); - res.info.populate(_block, strictness); - res.info.verifyInternals(&_block); - } - catch (Exception& ex) { - ex << errinfo_phase(1); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; + ReadGuard l(x_blocks); + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + return BlockInfo::extractHeader(&it->second).data().toBytes(); } - RLP r(_block); - unsigned i = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_uncleIndex(i); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; - } - i = 0; - for (RLP const& tr: r[1]) + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + + if (d.empty()) { - bytesConstRef d = tr.data(); - try - { - res.transactions.push_back(Transaction(d, CheckTransaction::Everything)); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_transactionIndex(i); - ex << errinfo_transaction(d.toBytes()); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; + cwarn << "Couldn't find requested block:" << _hash; + return bytes(); } - res.block = bytesConstRef(&_block); - return res; + + noteUsed(_hash); + + WriteGuard l(x_blocks); + m_blocks[_hash].resize(d.size()); + memcpy(m_blocks[_hash].data(), d.data(), d.size()); + + return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes(); } +State BlockChain::genesisState(OverlayDB const& _db) +{ + State ret(_db, BaseState::Empty); + dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? + ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. + ret.m_previousBlock = BlockInfo(&m_genesisBlock); + return ret; +} + + + + + + + + + + + + + + + + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 638c9c3af..50965f2b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,6 +37,7 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" +#include "State.h" namespace std { @@ -86,6 +87,13 @@ enum { }; using ProgressCallback = std::function; +using StateDefinition = std::unordered_map; + +class VersionChecker +{ +public: + VersionChecker(std::string const& _dbPath, h256 const& _genesisHash); +}; /** * @brief Implements the blockchain database. All data this gives is disk-backed. @@ -94,7 +102,7 @@ using ProgressCallback = std::function; class BlockChain { public: - BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); ~BlockChain(); /// Attempt a database re-open. @@ -120,14 +128,17 @@ public: /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; - /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. - BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); } + /// Get the partial-header of a block (or the most recent mined if none given). Thread-safe. + BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); } BlockInfo info() const { return info(currentHash()); } /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. bytes block(h256 const& _hash) const; bytes block() const { return block(currentHash()); } - bytes oldBlock(h256 const& _hash) const; + + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes headerData(h256 const& _hash) const; + bytes headerData() const { return headerData(currentHash()); } /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. BlockDetails details(h256 const& _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } @@ -264,13 +275,16 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); - /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); - /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } -private: + /// Get a pre-made genesis State object. + State genesisState(OverlayDB const& _db); + + /// Verify block and prepare it for enactment + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + +protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); @@ -345,6 +359,7 @@ private: /// Genesis block info. h256 m_genesisHash; bytes m_genesisBlock; + std::unordered_map m_genesisState; ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; @@ -354,6 +369,88 @@ private: friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; +template +class FullBlockChain: public BlockChain +{ +public: + using BlockHeader = typename Sealer::BlockHeader; + + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path, _we, _p) + {} + + /// Get the header of a block (or the most recent mined if none given). Thread-safe. + typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } + typename Sealer::BlockHeader header() const { return header(currentHash()); } + + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + { + VerifiedBlockRef res; + + try + { + BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); + h.verifyInternals(_block); + h.verifyParent(header(h.parentHash)); + res.info = static_cast(h); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + if (_ir && ImportRequirements::UncleBasic) + for (auto const& uncle: r[2]) + { + try + { + BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + if (_ir && ImportRequirements::TransactionBasic) + for (RLP const& tr: r[1]) + { + bytesConstRef d = tr.data(); + try + { + res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None)); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_transactionIndex(i); + ex << errinfo_transaction(d.toBytes()); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + res.block = bytesConstRef(_block); + return res; + } +}; + std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); } diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 2cf2a7583..a59326b77 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const for (unsigned i = 0; i < itemCount; ++i) { - auto h = BlockInfo::headerHash(_r[i].data()); + auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) + switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; @@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const logNewBlock(h); if (m_state == SyncState::NewBlocks) { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); + BlockInfo bi(_r[i].data()); if (bi.number > maxUnknownNumber) { maxUnknownNumber = bi.number; @@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP con { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); + auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { - switch (host().bq().import(_r[0].data(), host().chain())) + switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b6c548c1f..6b400b236 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); } catch (...) { @@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() } } -ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) +ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. - h256 h = BlockInfo::headerHash(_block); + h256 h = BlockInfo::headerHashFromBlock(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; @@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::AlreadyKnown; } - // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { - // TODO: quick verify - bi.populate(_block); - bi.verifyInternals(_block); + // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer + // VERIFY: populates from the block and checks the block is internally coherent. + bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info; } catch (Exception const& _e) { @@ -218,7 +216,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! - if (_bc.isKnown(h)) + if (m_bc->isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; @@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else @@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; @@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad) return !m_readySet.empty(); } -void BlockQueue::tick(BlockChain const& _bc) +void BlockQueue::tick() { vector> todo; { @@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc) cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) - import(&b.second, _bc); + import(&b.second); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index b9e6f5b3b..97fca7c72 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -76,11 +76,13 @@ public: BlockQueue(); ~BlockQueue(); + void setChain(BlockChain const& _bc) { m_bc = &_bc; } + /// Import a block into the queue. - ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. - void tick(BlockChain const& _bc); + void tick(); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. @@ -138,6 +140,8 @@ private: void updateBad_WITH_LOCK(h256 const& _bad); void drainVerified_WITH_BOTH_LOCKS(); + BlockChain const* m_bc; ///< The blockchain into which our imports go. + mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. h256Hash m_readySet; ///< All blocks ready for chain import. diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 4e6d89243..eee4b98b7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -41,14 +40,44 @@ namespace js = json_spirit; #define ETH_CATCH 1 -std::unordered_map const& dev::eth::genesisState() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); +std::string CanonBlockChain::s_genesisStateJSON; + +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) +{ +} + +bytes CanonBlockChain::createGenesisBlock() +{ + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + SecureTrieDB state(&db); + state.init(); + dev::eth::commit(createGenesisState(), state); + stateRoot = state.root(); + } + + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +unordered_map CanonBlockChain::createGenesisState() { static std::unordered_map s_ret; if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(c_genesisInfo, val); + json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()) { u256 balance; @@ -68,53 +97,29 @@ std::unordered_map const& dev::eth::genesisState() return s_ret; } -// TODO: place Registry in here. - -std::unique_ptr CanonBlockChain::s_genesis; -boost::shared_mutex CanonBlockChain::x_genesis; -Nonce CanonBlockChain::s_nonce(u64(42)); - -bytes CanonBlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - SecureTrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - BlockChain(createGenesisBlock(), _path, _we, _pc) +void CanonBlockChain::setGenesisState(std::string const& _json) { + WriteGuard l(x_genesis); + s_genesisStateJSON = _json; + s_genesis.reset(); } -void CanonBlockChain::setGenesisNonce(Nonce const& _n) +void CanonBlockChain::setGenesisNonce(Nonce const& _n) { WriteGuard l(x_genesis); s_nonce = _n; s_genesis.reset(); } -BlockInfo const& CanonBlockChain::genesis() +Ethash::BlockHeader const& CanonBlockChain::genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); - s_genesis.reset(new BlockInfo); - s_genesis->populate(&gb); + s_genesis.reset(new Ethash::BlockHeader); + s_genesis->populate(&gb, CheckEverything); } return *s_genesis; } diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index c16479f0d..d79926703 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BlockDetails.h" #include "Account.h" @@ -45,7 +46,32 @@ std::unordered_map const& genesisState(); * @threadsafe * @todo Make not memory hog (should actually act as a cache and deallocate old entries). */ -class CanonBlockChain: public BlockChain +template +class CanonBlockChain: public FullBlockChain +{ +public: + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + ~CanonBlockChain() {} + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock() + { + RLPStream block(3); + block.appendList(Sealer::BlockHeader::Fields) + << h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string(); + bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP(); + block.appendRaw(sealFields, Sealer::BlockHeader::SealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); + } +}; + +template <> +class CanonBlockChain: public FullBlockChain { public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} @@ -53,22 +79,35 @@ public: ~CanonBlockChain() {} /// @returns the genesis block header. - static BlockInfo const& genesis(); + static Ethash::BlockHeader const& genesis(); /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static std::unordered_map createGenesisState(); + /// Alter the value of the genesis block's nonce. /// @warning Unless you're very careful, make sure you call this right at the start of the /// program, before anything has had the chance to use this class at all. static void setGenesisNonce(Nonce const& _n); + /// Alter all the genesis block's state by giving a JSON string with account details. + /// @TODO implement. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisState(std::string const&); + + // TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, + private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + static std::unique_ptr s_genesis; static Nonce s_nonce; + static std::string s_genesisStateJSON; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 918480263..ec37302a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -72,47 +72,43 @@ static const Addresses c_canaries = Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph }; -VersionChecker::VersionChecker(string const& _dbPath) +Client::Client(std::shared_ptr _gp): + Worker("eth", 0), + m_gp(_gp ? _gp : make_shared()) { - upgradeDatabase(_dbPath); } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Client(_extNet, make_shared(), _dbPath, _forceAction, _networkId) +void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId) { - startWorking(); -} + // Cannot be opened until after blockchain is open, since BlockChain may upgrade the database. + // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database + // until after the construction. + m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); + m_preMine = State(m_stateDB); + m_postMine = State(m_stateDB); + // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. + m_preMine = bc().genesisState(m_stateDB); -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth", 0), - m_vc(_dbPath), - m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), - m_gp(_gp), - m_stateDB(State::openDB(_dbPath, _forceAction)), - m_preMine(m_stateDB, BaseState::CanonGenesis), - m_postMine(m_stateDB) -{ - if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + m_bq.setChain(bc()); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_sealEngine = shared_ptr(Ethash::createSealEngine()); - m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); + bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_gp->update(m_bc); + if (_forceAction == WithExisting::Rescue) + m_bc.rescue(m_stateDB); + + m_gp->update(bc()); - auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); + auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId)); m_host = host; _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common if (_dbPath.size()) Defaults::setDBPath(_dbPath); doWork(); - startWorking(); } @@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000) this_thread::sleep_for(std::chrono::milliseconds(500)); - return m_bq.import(&_block, bc(), _isSafe); + return m_bq.import(&_block, _isSafe); } tuple Client::syncQueue(unsigned _max) { stopWorking(); - return m_bc.sync(m_bq, m_stateDB, _max); + return bc().sync(m_bq, m_stateDB, _max); } void Client::onBadBlock(Exception& _ex) const @@ -294,7 +290,7 @@ void Client::startedWorking() clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -309,7 +305,7 @@ void Client::doneWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -328,7 +324,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.disable(); + m_sealEngine->cancelGeneration(); { WriteGuard l(x_postMine); @@ -340,10 +336,10 @@ void Client::killChain() m_working = State(); m_stateDB = OverlayDB(); - m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); - m_bc.reopen(Defaults::dbPath(), WithExisting::Kill); + m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); + bc().reopen(Defaults::dbPath(), WithExisting::Kill); - m_preMine = State(m_stateDB, BaseState::CanonGenesis); + m_preMine = bc().genesisState(m_stateDB); m_postMine = State(m_stateDB); } @@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); - auto receipts = m_bc.receipts(_block).receipts; + auto d = bc().info(_block); + auto receipts = bc().receipts(_block).receipts; Guard l(x_filtersWatches); io_changed.insert(ChainChangedFilter); @@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable) startMining(); } -MiningProgress Client::miningProgress() const +bool Client::isMining() const { - if (m_farm.isMining()) - return m_farm.miningProgress(); - return MiningProgress(); + return Ethash::isWorking(m_sealEngine.get()); +} + +WorkingProgress Client::miningProgress() const +{ + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()); + return WorkingProgress(); } uint64_t Client::hashrate() const { - if (m_farm.isMining()) - return m_farm.miningProgress().rate(); + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()).rate(); return 0; } @@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -ProofOfWork::WorkPackage Client::getWork() -{ - // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. - // this will be reset as soon as a new block arrives, allowing more transactions to be processed. - bool oldShould = shouldServeWork(); - m_lastGetWork = chrono::system_clock::now(); - - if (!m_mineOnBadChain && isChainBad()) - return ProofOfWork::WorkPackage(); - - // if this request has made us bother to serve work, prep it now. - if (!oldShould && shouldServeWork()) - onPostStateChanged(); - else - // otherwise, set this to true so that it gets prepped next time. - m_remoteWorking = true; - return ProofOfWork::package(m_miningInfo); -} - -bool Client::submitWork(ProofOfWork::Solution const& _solution) -{ - bytes newBlock; - DEV_WRITE_GUARDED(x_working) - if (!m_working.completeMine(_solution)) - return false; - - DEV_READ_GUARDED(x_working) - { - DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; - newBlock = m_working.blockData(); - } - - // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. - m_bq.import(&newBlock, m_bc, true); - - return true; -} - unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; @@ -553,7 +515,7 @@ void Client::syncBlockQueue() ImportRoute ir; unsigned count; Timer t; - tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); if (count) @@ -577,7 +539,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; DEV_WRITE_GUARDED(x_working) - tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp); if (newPendingReceipts.empty()) return; @@ -590,7 +552,7 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restart mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& h: _ir.deadBlocks) { clog(ClientTrace) << "Dead block:" << h; - for (auto const& t: m_bc.transactions(h)) + for (auto const& t: bc().transactions(h)) { clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, IfDropped::Retry); @@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir) newPreMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + preChanged = newPreMine.sync(bc()); if (preChanged || m_postMine.address() != m_preMine.address()) { @@ -700,7 +662,7 @@ void Client::rejigMining() { clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) - m_working.commitToMine(m_bc, m_extraData); + m_working.commitToMine(bc(), m_extraData); DEV_READ_GUARDED(x_working) { DEV_WRITE_GUARDED(x_postMine) @@ -709,10 +671,10 @@ void Client::rejigMining() } if (m_wouldMine) - m_farm.sealBlock(m_miningInfo); + m_sealEngine->generateSeal(m_miningInfo); } if (!m_wouldMine) - m_farm.disable(); + m_sealEngine->cancelGeneration(); } void Client::noteChanged(h256Hash const& _filters) @@ -768,7 +730,7 @@ void Client::tick() { m_report.ticks++; checkWatchGarbage(); - m_bq.tick(m_bc); + m_bq.tick(); m_lastTick = chrono::system_clock::now(); if (m_report.ticks == 15) clog(ClientTrace) << activityReport(); @@ -792,7 +754,7 @@ void Client::checkWatchGarbage() uninstallWatch(i); // blockchain GC - m_bc.garbageCollect(); + bc().garbageCollect(); m_lastGarbageCollection = chrono::system_clock::now(); } @@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const try { State ret(m_stateDB); - ret.populateFromChain(m_bc, _block); + ret.populateFromChain(bc(), _block); return ret.fromPending(_txi); } catch (Exception& ex) @@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const try { State ret(m_stateDB); - PopulationStatistics s = ret.populateFromChain(m_bc, _block); + PopulationStatistics s = ret.populateFromChain(bc(), _block); if (o_stats) swap(s, *o_stats); return ret; @@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const auto h = m_host.lock(); return h ? h->status() : SyncStatus(); } + +bool Client::submitSealed(bytes const& _header) +{ + DEV_WRITE_GUARDED(x_working) + if (!m_working.sealBlock(_header)) + return false; + + bytes newBlock; + DEV_READ_GUARDED(x_working) + { + DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + newBlock = m_working.blockData(); + } + + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. + return m_bq.import(&newBlock, true) == ImportResult::Success; +} + + + + + + + + + + + + + + +std::tuple EthashClient::getEthashWork() +{ + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); + m_lastGetWork = chrono::system_clock::now(); + + if (!m_mineOnBadChain && isChainBad()) + return std::tuple(); + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; + Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + return std::tuple(bh.boundary(), bh.hashWithout(), bh.seedHash()); +} + +bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce) +{ + Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce); + return true; +} + diff --git a/libethereum/Client.h b/libethereum/Client.h index 9ae7c7e09..73609bd71 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -60,12 +60,6 @@ enum ClientWorkState Deleted }; -class VersionChecker -{ -public: - VersionChecker(std::string const& _dbPath); -}; - struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; @@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); /** * @brief Main API hub for interfacing with Ethereum. + * Not to be used directly - subclass. */ class Client: public ClientBase, Worker { public: /// New-style Constructor. - explicit Client( - p2p::Host* _host, - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); - - explicit Client( - p2p::Host* _host, - std::shared_ptr _gpForAdoption, // pass it in with new. - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); + /// Any final derived class's constructor should make sure they call init(). + explicit Client(std::shared_ptr _gpForAdoption); /// Destructor. virtual ~Client(); @@ -129,7 +112,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. - CanonBlockChain const& blockChain() const { return m_bc; } + BlockChain const& blockChain() const { return bc(); } /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. @@ -176,26 +159,16 @@ public: /// NOT thread-safe void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? - bool isMining() const override { return m_farm.isMining(); } + bool isMining() const override; /// Are we mining now? bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MiningProgress miningProgress() const override; + WorkingProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); - /// Update to the latest transactions and get hash of the current block to be mined minus the - /// nonce (the 'work hash') and the difficulty to be met. - virtual ProofOfWork::WorkPackage getWork() override; - - /** @brief Submit the proof for the proof-of-work. - * @param _s A valid solution. - * @return true if the solution was indeed valid and accepted. - */ - virtual bool submitWork(ProofOfWork::Solution const& _proof) override; - // Debug stuff: DownloadMan const* downloadMan() const; @@ -218,12 +191,20 @@ public: /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } /// Rewind to a prior head. - void rewind(unsigned _n) { m_bc.rewind(_n); } + void rewind(unsigned _n) { bc().rewind(_n); } + /// Rescue the chain. + void rescue() { bc().rescue(m_stateDB); } + /// Get the seal engine. + SealEngineFace* sealEngine() const { return m_sealEngine.get(); } protected: + /// Perform critical setup functions. + /// Must be called in the constructor of the finally derived class. + void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); + /// InterfaceStub methods - virtual BlockChain& bc() override { return m_bc; } - virtual BlockChain const& bc() const override { return m_bc; } + virtual BlockChain& bc() override = 0; + virtual BlockChain const& bc() const override = 0; /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. @@ -245,7 +226,10 @@ protected: /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. void noteChanged(h256Hash const& _filters); -private: + /// Submit + bool submitSealed(bytes const& _s); + +protected: /// Called when Worker is starting. void startedWorking() override; @@ -291,8 +275,6 @@ private: /// @warning May be called from any thread. void onBadBlock(Exception& _ex) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -339,5 +321,64 @@ private: bytes m_extraData; }; +template +class SpecialisedClient: public Client +{ +public: + explicit SpecialisedClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): + Client(_gpForAdoption), + m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }) + { + m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSealGenerated([=](bytes const& header){ + return this->submitSealed(header); + }); + init(_host, _dbPath, _forceAction, _networkId); + } + + /// Get the object representing the current canonical blockchain. + CanonBlockChain const& blockChain() const { return m_bc; } + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } + +protected: + CanonBlockChain m_bc; ///< Maintains block database. +}; + +class EthashClient: public SpecialisedClient +{ +public: + /// Trivial forwarding constructor. + explicit EthashClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + + /// Update to the latest transactions and get hash of the current block to be mined minus the + /// nonce (the 'work hash') and the difficulty to be met. + virtual std::tuple getEthashWork() override; + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ + virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } +}; + } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f463b0195..769880269 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const auto bl = bc().block(_blockHash); RLP b(bl); if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); + return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData); else return BlockInfo(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 82f03def0..874f10548 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -156,9 +156,7 @@ public: virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } - virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } - virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } - virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } + virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 973433af9..213e7fb26 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" @@ -207,12 +207,12 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual ProofOfWork::WorkPackage getWork() = 0; + virtual std::tuple getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); } /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; + virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); } /// Check the progress of the mining. - virtual MiningProgress miningProgress() const = 0; + virtual WorkingProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1656109a9..ee2078a07 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } -OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) +OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; @@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) boost::filesystem::remove_all(path + "/state"); } - path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); + path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); ldb::Options o; @@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("beginning of Genesis construction.", true); - if (_bs == BaseState::CanonGenesis) - { - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); - - paranoia("after DB commit of Genesis construction.", true); - m_previousBlock = CanonBlockChain::genesis(); - } - else - m_previousBlock.clear(); - - resetCurrent(); - - assert(m_state.root() == m_previousBlock.stateRoot); + m_previousBlock.clear(); + m_currentBlock.clear(); +// assert(m_state.root() == m_previousBlock.stateRoot); paranoia("end of normal construction.", true); } @@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip; - bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip, _ir); + BlockInfo bip(_bc.block(bi.parentHash)); + sync(_bc, bi.parentHash, bip); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; - auto vb = BlockChain::verifyBlock(b); + auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); t.restart(); - enact(vb, _bc, _ir); + enact(vb, _bc); ret.enact = t.elapsed(); } else @@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi, _ir); + sync(_bc, _h, bi); } return ret; @@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ void State::commit() { - m_touched += dev::eth::commit(m_cache, m_db, m_state); + m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } @@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) +bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi) { - (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -355,7 +342,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor { cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; - cwarn << "Bailing."; + cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); } m_previousBlock = bi; @@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) { #if ETH_TIMED_ENACTMENTS Timer t; @@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _ir); + auto ret = enact(_block, _bc); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire RLP rlp(_block); cleanup(false); - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal); m_currentBlock = bi; m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); @@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) { DEV_TIMED_FUNCTION_ABOVE(500); @@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = _block.info; m_currentBlock.noteDirty(); + m_currentBlock = _block.info; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } @@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + // IgnoreSeal since it's a VerifiedBlock. + BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; if (!_bc.isKnown(uncle.parentHash)) @@ -829,6 +817,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { + (void)_bc; + /* commitToMine(_bc); // Update difficulty according to timestamp. @@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out(), std::function(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) { cwarn << "Bad block: " << _e.what(); } - +*/ return false; } @@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) for (auto const& u: us) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { - BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithProof); + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); ++unclesCount; - uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) break; } @@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) m_committedToMine = true; } -void State::completeMine() +bool State::sealBlock(bytesConstRef _header) { - cdebug << "Completing mine!"; + if (!m_committedToMine) + return false; + + cdebug << "Sealing block!"; // Got it! // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithProof); + ret.appendRaw(_header); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); - m_currentBlock.noteDirty(); + m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; -/* StructuredLogger::minedNewBlock( + // TODO: move into Sealer + StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.proof.nonce.abridged(), + "", // Can't give the nonce here. "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - );*/ + ); // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. @@ -989,6 +982,8 @@ void State::completeMine() m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; + + return true; } bool State::addressInUse(Address _id) const diff --git a/libethereum/State.h b/libethereum/State.h index f6a8471ea..805215ee5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "Account.h" @@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati enum class BaseState { PreExisting, - Empty, - CanonGenesis + Empty }; enum class Permanence @@ -104,6 +102,7 @@ class State friend class dev::test::ImportTest; friend class dev::test::StateLoader; friend class Executive; + friend class BlockChain; public: /// Default constructor; creates with a blank database prepopulated with the genesis block. @@ -125,7 +124,7 @@ public: ~State(); /// Construct state object from arbitrary point in blockchain. - PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None); /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. @@ -133,8 +132,8 @@ public: Address address() const { return m_ourAddress; } /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. - static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust); - static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } + static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); } OverlayDB const& db() const { return m_db; } OverlayDB& db() { return m_db; } @@ -163,22 +162,20 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. - template - bool completeMine(typename PoW::Solution const& _result) - { - if (!m_committedToMine) - return false; - - m_currentBlock.proof = _result; - if (!PoW::verify(m_currentBlock)) - return false; - -// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - - completeMine(); - - return true; - } + /// TODO: verify it prior to calling this. + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * while (notYetMined) + * { + * // lock + * commitToMine(_blockChain); // will call uncommitToMine if a repeat. + * completeMine(); + * // unlock + * @endcode + */ + bool sealBlock(bytes const& _header) { return sealBlock(&_header); } + bool sealBlock(bytesConstRef _header); /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. @@ -295,11 +292,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); + bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -313,19 +310,6 @@ public: void resetCurrent(); private: - /** Commit to DB and build the final block if the previous call to mine()'s result is completion. - * Typically looks like: - * @code - * while (notYetMined) - * { - * // lock - * commitToMine(_blockChain); // will call uncommitToMine if a repeat. - * completeMine(); - * // unlock - * @endcode - */ - void completeMine(); - /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -340,7 +324,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -386,7 +370,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, SecureTrieDB& _state) { AddressHash ret; for (auto const& i: _cache) @@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, } else { - SecureTrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); @@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, if (i.second.isFreshCode()) { h256 ch = sha3(i.second.code()); - _db.insert(ch, &i.second.code()); + _state.db()->insert(ch, &i.second.code()); s << ch; } else diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index e02012cd5..1b97f82e7 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args) return m_data; } -void dev::eth::upgradeDatabase(std::string const& _basePath) +void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash) { std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath; @@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath) { auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; - auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash; string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(databaseVersion); diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 0dfe8509b..df48269ec 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -42,7 +43,7 @@ namespace eth */ bytes parseData(std::string const& _args); -void upgradeDatabase(std::string const& _basePath); +void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash); } } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 7d63ed165..15d39bded 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); -#if ETH_USING_ETHASH // TODO: move into ProofOfWork. - res["nonce"] = toJS(_bi.proof.nonce); - res["seedHash"] = toJS(_bi.proofCache()); -#endif +// res["nonce"] = toJS(_bi.proof.nonce); +// res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..624a73e54 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. +template +Json::Value toJson(BlockHeaderPolished const& _bh) +{ + Json::Value res; + if (_bh) + { + res = toJson(static_cast(_bh)); + for (auto const& i: _bh.jsInfo()) + res[i.first] = i.second; + } + return res; +} + } namespace shh diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 1743882e5..061b5ae79 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -24,7 +24,6 @@ #include #include "../JsonSpiritHeaders.h" #include -#include #include #include #include "../TestHelper.h" @@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - Ethash::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 452163061..e3f8ac29f 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. From 1e6bf809b4849fbd037acf3acf6e343b2dd8e788 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:29:03 +0200 Subject: [PATCH 054/113] All fields of BlockInfo now private. --- alethzero/MainWin.cpp | 34 +++--- ethminer/MinerAux.h | 4 +- evmjit/libevmjit-cpp/JitVM.cpp | 6 +- evmjit/libevmjit/RuntimeManager.cpp | 6 +- exp/main.cpp | 6 +- libethcore/BasicAuthority.cpp | 8 +- libethcore/BlockInfo.cpp | 104 ++++++++--------- libethcore/BlockInfo.h | 91 +++++++++------ libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 40 +++---- libethcore/EthashAux.cpp | 2 +- libethereum/BasicGasPricer.cpp | 6 +- libethereum/BlockChain.cpp | 78 +++++-------- libethereum/BlockChain.h | 2 +- libethereum/BlockChainSync.cpp | 6 +- libethereum/BlockQueue.cpp | 50 ++++---- libethereum/Executive.cpp | 10 +- libethereum/State.cpp | 133 +++++++++++----------- libethereum/State.h | 2 +- libevm/ExtVMFace.h | 4 +- libevm/VM.cpp | 10 +- libtestutils/BlockChainLoader.cpp | 2 +- libweb3jsonrpc/JsonHelper.cpp | 22 ++-- test/TestHelper.cpp | 6 +- test/libethereum/ClientBase.cpp | 18 +-- test/libethereum/blockchain.cpp | 78 ++++++------- test/libethereum/genesis.cpp | 2 +- test/libevm/vm.cpp | 12 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- third/MainWin.cpp | 2 +- 30 files changed, 378 insertions(+), 370 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2ee8928f5..ad8f5528c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,7 +189,7 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; @@ -1629,7 +1629,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1706,7 +1706,7 @@ void Main::on_blocks_currentItemChanged() if (item->data(Qt::UserRole + 1).isNull()) { char timestamp[64]; - time_t rawTime = (time_t)(uint64_t)info.timestamp; + time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; s << "

#" << info.number; @@ -1714,7 +1714,7 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; - s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "" << "
"; + s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; @@ -1724,7 +1724,7 @@ void Main::on_blocks_currentItemChanged() { auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; - s << "
Parent: " << info.parentHash << "" << "
"; + s << "
Parent: " << info.parentHash() << "" << "
"; } else { @@ -1732,20 +1732,20 @@ void Main::on_blocks_currentItemChanged() s << "
Parent: It was a virgin birth
"; } // s << "
Bloom: " << details.bloom << ""; - if (!!info.logBloom) - s << "
Log Bloom: " << info.logBloom << "
"; + if (!!info.logBloom()) + s << "
Log Bloom: " << info.logBloom() << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; - s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Parent: " << uncle.parentHash() << "" << ""; s << line << "Number: " << uncle.number << "" << ""; - s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; @@ -1754,20 +1754,20 @@ void Main::on_blocks_currentItemChanged() auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } - if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; + if (info.parentHash()) + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; else s << "
Pre: Nothing is before Phil" << "
"; - s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; + s << "
Receipts: @" << info.receiptsRoot() << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Post: " << info.stateRoot() << "" << "
"; s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } @@ -1807,7 +1807,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 61fde605d..0d227b1ef 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -398,8 +398,8 @@ private: void doInitDAG(unsigned _n) { BlockInfo bi; - bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; + bi.number() = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 2fb2a0e67..4e1fb66ea 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -24,7 +24,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index d48b64bb1..b2c15d7ae 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,7 +1,7 @@ #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" #include "Stack.h" @@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; + case RuntimeData::Timestamp: return "block.timestamp()"; case RuntimeData::Code: return "code.ptr"; case RuntimeData::CodeSize: return "code.size"; } diff --git a/exp/main.cpp b/exp/main.cpp index 4a35068f1..0b740e526 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,8 +85,8 @@ int main() BlockInfo bi; bi.difficulty = c_genesisDifficulty; bi.gasLimit = c_genesisGasLimit; - bi.number = 1; - bi.parentHash = sha3("parentHash"); + bi.number() = 1; + bi.parentHash() = sha3("parentHash"); bytes sealedData; @@ -329,7 +329,7 @@ int main() mine(s, bc, se); bytes minedBlock = s.blockData(); - cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot(); bc.import(minedBlock, stateDB); cnote << bc; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 22da67080..7ef3dd21e 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -44,19 +44,19 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri m_sig = _header[BlockInfo::BasicFields].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); BOOST_THROW_EXCEPTION(ex); } } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 64961bc40..266f57cc8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -BlockInfo::BlockInfo(): timestamp(Invalid256) +BlockInfo::BlockInfo(): m_timestamp(Invalid256) { } @@ -45,26 +45,26 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, void BlockInfo::clear() { - parentHash = h256(); - sha3Uncles = EmptyListSHA3; - coinbaseAddress = Address(); - stateRoot = EmptyTrie; - transactionsRoot = EmptyTrie; - receiptsRoot = EmptyTrie; - logBloom = LogBloom(); - difficulty = 0; - number = 0; - gasLimit = 0; - gasUsed = 0; - timestamp = 0; - extraData.clear(); + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_coinbaseAddress = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = 0; + m_extraData.clear(); noteDirty(); } h256 const& BlockInfo::boundary() const { - if (!m_boundary && difficulty) - m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); + if (!m_boundary && m_difficulty) + m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty); return m_boundary; } @@ -81,8 +81,8 @@ h256 const& BlockInfo::hashWithout() const void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << gasLimit << gasUsed << timestamp << extraData; + _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; } h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) @@ -110,19 +110,19 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { - parentHash = _header[field = 0].toHash(RLP::VeryStrict); - sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); - coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); - stateRoot = _header[field = 3].toHash(RLP::VeryStrict); - transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); - receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); - logBloom = _header[field = 6].toHash(RLP::VeryStrict); - difficulty = _header[field = 7].toInt(); - number = _header[field = 8].toInt(); - gasLimit = _header[field = 9].toInt(); - gasUsed = _header[field = 10].toInt(); - timestamp = _header[field = 11].toInt(); - extraData = _header[field = 12].toBytes(); + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toInt(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toInt(); + m_extraData = _header[field = 12].toBytes(); } catch (Exception const& _e) { @@ -130,11 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) throw; } - if (number > ~(unsigned)0) + if (m_number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing && gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); + if (_s != CheckNothing && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -147,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); - if (transactionsRoot != expectedRoot) + if (m_transactionsRoot != expectedRoot) { MemoryDB tm; GenericTrieDB transactionsTrie(&tm); @@ -172,52 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) cdebug << toHex(t); - BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot)); + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); - if (sha3Uncles != sha3(root[2].data())) + if (m_sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } void BlockInfo::populateFromParent(BlockInfo const& _parent) { - stateRoot = _parent.stateRoot; - number = _parent.number + 1; - gasLimit = selectGasLimit(_parent); - gasUsed = 0; - difficulty = calculateDifficulty(_parent); - parentHash = _parent.hash(); + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_gasLimit = selectGasLimit(_parent); + m_gasUsed = 0; + m_difficulty = calculateDifficulty(_parent); + m_parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return c_genesisGasLimit; else // target minimum of 3141592 - if (_parent.gasLimit < c_genesisGasLimit) - return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + if (_parent.m_gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return (u256)c_genesisDifficulty; else - return max(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor))); + return max(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); } void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check timestamp is after previous timestamp. - if (parentHash) + if (m_parentHash) { - if (timestamp <= _parent.timestamp) + if (m_timestamp <= _parent.m_timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); - if (number != _parent.number + 1) + if (m_number != _parent.m_number + 1) BOOST_THROW_EXCEPTION(InvalidNumber()); } } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b00fa73fb..67a5397f4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -81,21 +81,6 @@ struct BlockInfo public: static const unsigned BasicFields = 13; - // TODO: make them all private! - h256 parentHash; - h256 sha3Uncles; - Address coinbaseAddress; - h256 stateRoot; - h256 transactionsRoot; - h256 receiptsRoot; - LogBloom logBloom; - u256 difficulty; // TODO: pull out into BlockHeader - u256 number; - u256 gasLimit; - u256 gasUsed; - u256 timestamp = Invalid256; - bytes extraData; - BlockInfo(); explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} @@ -104,23 +89,23 @@ public: static h256 headerHashFromBlock(bytesConstRef _block); static RLP extractHeader(bytesConstRef _block); - explicit operator bool() const { return timestamp != Invalid256; } + explicit operator bool() const { return m_timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { - return parentHash == _cmp.parentHash && - sha3Uncles == _cmp.sha3Uncles && - coinbaseAddress == _cmp.coinbaseAddress && - stateRoot == _cmp.stateRoot && - transactionsRoot == _cmp.transactionsRoot && - receiptsRoot == _cmp.receiptsRoot && - logBloom == _cmp.logBloom && - difficulty == _cmp.difficulty && - number == _cmp.number && - gasLimit == _cmp.gasLimit && - gasUsed == _cmp.gasUsed && - timestamp == _cmp.timestamp && - extraData == _cmp.extraData; + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_coinbaseAddress == _cmp.coinbaseAddress() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } @@ -132,6 +117,31 @@ public: u256 selectGasLimit(BlockInfo const& _parent) const; h256 const& boundary() const; + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); } + void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + + Address const& coinbaseAddress() const { return m_coinbaseAddress; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& timestamp() const { return m_timestamp; } + bytes const& extraData() const { return m_extraData; } + + u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader + /// sha3 of the header only. h256 const& hashWithout() const; h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } @@ -145,6 +155,21 @@ protected: mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + h256 m_parentHash; + h256 m_sha3Uncles; + Address m_coinbaseAddress; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + u256 m_number; + u256 m_gasLimit; + u256 m_gasUsed; + u256 m_timestamp = Invalid256; + bytes m_extraData; + + u256 m_difficulty; // TODO: pull out into BlockHeader + private: mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty @@ -152,9 +177,9 @@ private: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp; + _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); return _out; } @@ -191,7 +216,7 @@ public: // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { - if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); BlockInfoSub::verifyParent(_parent); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 499854584..05cc45280 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -124,7 +124,7 @@ static void badBlockInfo(BlockInfo const& _bi, string const& _err) ss << c_space << endl; ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_space << endl; - string bin = toString(_bi.number); + string bin = toString(_bi.number()); ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; ss << c_space << endl; ss << c_line; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 128822b80..ee483aa8b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ namespace eth h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); + m_seedHash = EthashAux::seedHash((unsigned)m_number); return m_seedHash; } @@ -72,7 +72,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_nonce(m_nonce); @@ -81,42 +81,42 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } if (_s != CheckNothing) { - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + if (m_difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) ); - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + if (m_gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) ); - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + if (m_number && m_extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size()))); } } void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) { // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + if (m_difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty)); - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); + if (m_gasLimit < c_minGasLimit || + m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor || + m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)); } void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) @@ -126,7 +126,7 @@ void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) bool Ethash::BlockHeaderRaw::preVerify() const { - if (number >= ETHASH_EPOCH_LENGTH * 2048) + if (m_number >= ETHASH_EPOCH_LENGTH * 2048) return false; bool ret = !!ethash_quick_check_difficulty( @@ -162,7 +162,7 @@ bool Ethash::BlockHeaderRaw::verify() const cwarn << "headerHash:" << hashWithout(); cwarn << "nonce:" << m_nonce; cwarn << "mixHash:" << m_mixHash; - cwarn << "difficulty:" << difficulty; + cwarn << "difficulty:" << m_difficulty; cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; @@ -290,7 +290,7 @@ public: m_farm.setWork(m_sealing); m_farm.start(m_sealer); m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number); + Ethash::ensurePrecomputed((unsigned)_bi.number()); } void onSealGenerated(std::function const& _f) override { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index c511978db..763bea417 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,7 +63,7 @@ EthashAux* EthashAux::get() uint64_t EthashAux::cacheSize(BlockInfo const& _header) { - return ethash_get_cachesize((uint64_t)_header.number); + return ethash_get_cachesize((uint64_t)_header.number()); } uint64_t EthashAux::dataSize(uint64_t _blockNumber) diff --git a/libethereum/BasicGasPricer.cpp b/libethereum/BasicGasPricer.cpp index 145d23594..b957966f8 100644 --- a/libethereum/BasicGasPricer.cpp +++ b/libethereum/BasicGasPricer.cpp @@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; h256 p = _bc.currentHash(); - m_gasPerBlock = _bc.info(p).gasLimit; + m_gasPerBlock = _bc.info(p).gasLimit(); map dist; u256 total = 0; @@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc) while (c < 1000 && p) { BlockInfo bi = _bc.info(p); - if (bi.transactionsRoot != EmptyTrie) + if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); @@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc) i++; } } - p = bi.parentHash; + p = bi.parentHash(); ++c; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aae8cbd10..b696c77bd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) { try { BlockInfo d(bytesConstRef(it->value())); - _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; + _out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; } catch (...) { cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); @@ -293,11 +293,11 @@ void BlockChain::rebuild(std::string const& _path, std::function parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1); + cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); return; } lastHash = bi.hash(); @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -461,21 +461,21 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Work out its number as the parent's number + 1 - if (!isKnown(_block.info.parentHash)) + if (!isKnown(_block.info.parentHash())) { - clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash(); // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_block.info.parentHash); + auto pd = details(_block.info.parentHash()); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_block.info.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; + auto parentBlock = block(_block.info.parentHash()); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash()); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number(); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -483,9 +483,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Check it's not crazy - if (_block.info.timestamp > (u256)time(0)) + if (_block.info.timestamp() > (u256)time(0)) { - clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } @@ -543,9 +543,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_block.info.parentHash); + details(_block.info.parentHash()); DEV_WRITE_GUARDED(x_details) - m_details[_block.info.parentHash].children.push_back(_block.info.hash()); + m_details[_block.info.parentHash()].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); @@ -554,9 +554,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp())); - extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); @@ -585,10 +585,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif - // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; h256 common; @@ -599,7 +599,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash()); route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be @@ -630,15 +630,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Collate logs into blooms. h256s alteredBlooms; { - LogBloom blockBloom = tbi.logBloom; - blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); + LogBloom blockBloom = tbi.logBloom(); + blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref())); // Pre-memoize everything we need before locking x_blocksBlooms - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) blocksBlooms(chunkId(level, index / c_bloomIndexSize)); WriteGuard l(x_blocksBlooms); - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) { unsigned i = index / c_bloomIndexSize; unsigned o = index % c_bloomIndexSize; @@ -661,23 +661,23 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& ReadGuard l1(x_blocksBlooms); for (auto const& h: alteredBlooms) extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); - extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); + extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); } // FINALLY! change our best hash. { newLastBlockHash = _block.info.hash(); - newLastBlockNumber = (unsigned)_block.info.number; + newLastBlockNumber = (unsigned)_block.info.number(); } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; #if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif } @@ -750,7 +750,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& checkBest = t.elapsed(); if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number(); cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; @@ -758,7 +758,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; cnote << " " << _block.transactions.size() << " transactions"; - cnote << " " << _block.info.gasUsed << " gas used"; + cnote << " " << _block.info.gasUsed() << " gas used"; } #endif @@ -861,7 +861,7 @@ void BlockChain::rescue(OverlayDB& _db) cout << "extras..." << flush; details(h); cout << "state..." << flush; - if (_db.exists(bi.stateRoot)) + if (_db.exists(bi.stateRoot())) break; } catch (...) {} @@ -1233,19 +1233,3 @@ State BlockChain::genesisState(OverlayDB const& _db) return ret; } - - - - - - - - - - - - - - - - diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50965f2b6..3ff85c8a6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -391,7 +391,7 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash)); + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index a59326b77..64d1bb197 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr _peer) unsigned BlockChainSync::estimatedHashes() const { BlockInfo block = host().chain().info(); - time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp(); time_t now = time(0); unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) @@ -220,9 +220,9 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); - if (bi.number > maxUnknownNumber) + if (bi.number() > maxUnknownNumber) { - maxUnknownNumber = bi.number; + maxUnknownNumber = bi.number(); maxUnknown = h; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6b400b236..c9ee4c1cf 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,8 +101,8 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.sha3Uncles = work.hash; - bi.parentHash = work.parentHash; + bi.setSha3Uncles(work.hash); + bi.setParentHash(work.parentHash); m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.sha3Uncles == work.hash) + if (it->verified.info.sha3Uncles() == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,11 +136,11 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash) { // we're next! m_verifying.pop_front(); - if (m_knownBad.count(res.verified.info.parentHash)) + if (m_knownBad.count(res.verified.info.parentHash())) { m_readySet.erase(res.verified.info.hash()); m_knownBad.insert(res.verified.info.hash()); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.sha3Uncles == work.hash) + if (i.verified.info.sha3Uncles() == work.hash) { i = move(res); goto OK; @@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() { while (!m_verifying.empty() && !m_verifying.front().blockData.empty()) { - if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + if (m_knownBad.count(m_verifying.front().verified.info.parentHash())) { m_readySet.erase(m_verifying.front().verified.info.hash()); m_knownBad.insert(m_verifying.front().verified.info.hash()); @@ -213,7 +213,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) return ImportResult::Malformed; } - clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash(); // Check block doesn't already exist first! if (m_bc->isKnown(h)) @@ -227,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // Check it's not in the future (void)_isOurs; - if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) + if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/) { - m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); + m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes()))); char buf[24]; - time_t bit = (unsigned)bi.timestamp; + time_t bit = (unsigned)bi.timestamp(); if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails - clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp() << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); + m_difficulty += bi.difficulty(); + bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash()); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. - if (m_knownBad.count(bi.parentHash)) + if (m_knownBad.count(bi.parentHash())) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash())) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; - m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash(); + m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_unknownCount++; return ImportResult::UnknownParent; @@ -268,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash(), _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_knownCount++; noteReady_WITH_LOCK(h); @@ -295,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::vector oldVerified; swap(m_verified, oldVerified); for (auto& b: oldVerified) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash())) { m_knownBad.insert(b.verified.info.hash()); m_readySet.erase(b.verified.info.hash()); @@ -321,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles())) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles(); m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); @@ -460,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; + m_drainingDifficulty += bs.verified.info.difficulty(); m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 866c9c8f9..e58e1a8c6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), + m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)), m_depth(_level) {} @@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction) // Avoid transactions that would take us beyond the block gas limit. u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) + if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit()) { - clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; - BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas())); } // Check gas cost is enough. @@ -403,7 +403,7 @@ void Executive::finalize() m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); - m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); + m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned); // Suicides... if (m_ext) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ee2078a07..64daaf5f8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -105,7 +105,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock.clear(); m_currentBlock.clear(); -// assert(m_state.root() == m_previousBlock.stateRoot); +// assert(m_state.root() == m_previousBlock.stateRoot()); paranoia("end of normal construction.", true); } @@ -123,16 +123,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& auto b = _bc.block(_h); BlockInfo bi(b); - if (bi.number) + if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + BlockInfo bip(_bc.block(bi.parentHash())); + sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. - m_ourAddress = bi.coinbaseAddress; + m_ourAddress = bi.coinbaseAddress(); Timer t; auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); @@ -338,9 +338,9 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - if (m_db.lookup(bi.stateRoot).empty()) + if (m_db.lookup(bi.stateRoot()).empty()) { - cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; + cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); @@ -357,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash()); // push back for later replay. - bi.populate(_bc.block(bi.parentHash)); // move to parent. + bi.populate(_bc.block(bi.parentHash())); // move to parent. } m_previousBlock = bi; @@ -402,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif // Check family: - BlockInfo biParent = _bc.info(_block.info.parentHash); + BlockInfo biParent = _bc.info(_block.info.parentHash()); _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -411,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif BlockInfo biGrandParent; - if (biParent.number) - biGrandParent = _bc.info(biParent.parentHash); + if (biParent.number()) + biGrandParent = _bc.info(biParent.parentHash()); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo()); + sync(_bc, _block.info.parentHash(), BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -462,17 +462,15 @@ void State::resetCurrent() m_cache.clear(); m_touched.clear(); m_currentBlock = BlockInfo(); - m_currentBlock.coinbaseAddress = m_ourAddress; - m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); - m_currentBlock.transactionsRoot = h256(); - m_currentBlock.sha3Uncles = h256(); + m_currentBlock.setCoinbaseAddress(m_ourAddress); + m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0))); m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); m_committedToMine = false; @@ -538,7 +536,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu catch (BlockGasLimitReached const& e) { bigint const& got = *boost::get_error_info(e); - if (got > m_currentBlock.gasLimit) + if (got > m_currentBlock.gasLimit()) { clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; _tq.drop(t.sha3()); @@ -583,7 +581,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number()); string ret; unsigned i = 0; @@ -604,12 +602,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == _block.info.parentHash); - assert(m_currentBlock.parentHash == _block.info.parentHash); - assert(rootHash() == m_previousBlock.stateRoot); + assert(m_previousBlock.hash() == _block.info.parentHash()); + assert(m_currentBlock.parentHash() == _block.info.parentHash()); + assert(rootHash() == m_previousBlock.stateRoot()); #endif - if (m_currentBlock.parentHash != m_previousBlock.hash()) + if (m_currentBlock.parentHash() != m_previousBlock.hash()) // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); @@ -622,7 +620,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) LastHashes lh; DEV_TIMED_ABOVE("lastHashes", 500) - lh = _bc.lastHashes((unsigned)m_previousBlock.number); + lh = _bc.lastHashes((unsigned)m_previousBlock.number()); RLP rlp(_block.block); @@ -651,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) } h256 receiptsRoot; - DEV_TIMED_ABOVE("receiptsRoot", 500) + DEV_TIMED_ABOVE(".receiptsRoot()", 500) receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) + if (receiptsRoot != m_currentBlock.receiptsRoot()) { InvalidReceiptsStateRoot ex; - ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot()); ex << errinfo_receipts(receipts); ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } - if (m_currentBlock.logBloom != logBloom()) + if (m_currentBlock.logBloom() != logBloom()) { InvalidLogBloom ex; - ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom()); ex << errinfo_receipts(receipts); BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. - u256 tdIncrease = m_currentBlock.difficulty; + u256 tdIncrease = m_currentBlock.difficulty(); // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) @@ -686,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) vector rewarded; h256Hash excluded; DEV_TIMED_ABOVE("allKin", 500) - excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; @@ -710,22 +708,22 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) + if (!_bc.isKnown(uncle.parentHash())) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + uncleParent = BlockInfo(_bc.block(uncle.parentHash())); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7) { UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } - else if (uncle.number == m_currentBlock.number) + else if (uncle.number() == m_currentBlock.number()) { UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } uncle.verifyParent(uncleParent); @@ -748,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash()) { m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot())); } - if (m_currentBlock.gasUsed != gasUsed()) + if (m_currentBlock.gasUsed() != gasUsed()) { // Rollback the trie. m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed()))); } return tdIncrease; @@ -772,7 +770,7 @@ void State::cleanup(bool _fullCommit) // Commit the new trie to disk. if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -786,7 +784,7 @@ void State::cleanup(bool _fullCommit) m_db.commit(); if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -806,7 +804,7 @@ void State::uncommitToMine() { m_cache.clear(); if (!m_transactions.size()) - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); else m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; @@ -878,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock.number != 0) + if (m_previousBlock.number() != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); - auto p = m_previousBlock.parentHash; +// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl; + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; @@ -926,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = hash256(transactionsMap); - m_currentBlock.receiptsRoot = hash256(receiptsMap); - m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); - // Apply rewards last of all. applyRewards(uncleBlockHeaders); @@ -941,12 +934,18 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // cnote << m_state; // cnote << *this; - m_currentBlock.gasUsed = gasUsed(); - m_currentBlock.stateRoot = m_state.root(); - m_currentBlock.parentHash = m_previousBlock.hash(); - m_currentBlock.extraData = _extraData; - if (m_currentBlock.extraData.size() > 32) - m_currentBlock.extraData.resize(32); + m_currentBlock.setLogBloom(logBloom()); + m_currentBlock.setGasUsed(gasUsed()); + m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root()); + + m_currentBlock.setParentHash(m_previousBlock.hash()); + m_currentBlock.setExtraData(_extraData); + if (m_currentBlock.extraData().size() > 32) + { + auto ed = m_currentBlock.extraData(); + ed.resize(32); + m_currentBlock.setExtraData(ed); + } m_committedToMine = true; } @@ -967,13 +966,13 @@ bool State::sealBlock(bytesConstRef _header) ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); - cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; + cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")"; // TODO: move into Sealer StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), "", // Can't give the nonce here. "", //TODO: chain head hash here ?? - m_currentBlock.parentHash.abridged() + m_currentBlock.parentHash().abridged() ); // Quickly reset the transactions. @@ -1270,7 +1269,7 @@ State State::fromPending(unsigned _i) const ret.m_cache.clear(); _i = min(_i, m_transactions.size()); if (!_i) - ret.m_state.setRoot(m_previousBlock.stateRoot); + ret.m_state.setRoot(m_previousBlock.stateRoot()); else ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) @@ -1287,10 +1286,10 @@ void State::applyRewards(vector const& _uncleBlockHeaders) u256 r = m_blockReward; for (auto const& i: _uncleBlockHeaders) { - addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8); + addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8); r += m_blockReward / 32; } - addBalance(m_currentBlock.coinbaseAddress, r); + addBalance(m_currentBlock.coinbaseAddress(), r); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) diff --git a/libethereum/State.h b/libethereum/State.h index 805215ee5..e2bda6f24 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } + u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); } /// Check if the address is in use. bool addressInUse(Address _address) const; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..a5c45af26 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -83,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry ): LogEntry(_le), blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), + blockNumber((BlockNumber)_bi.number()), transactionHash(_th), transactionIndex(_ti), logIndex(_li), @@ -205,7 +205,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } + h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2b2ada0ae..f95481c54 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress()); break; case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); + m_stack.push_back(_ext.currentBlock.timestamp()); break; case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); + m_stack.push_back(_ext.currentBlock.number()); break; case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); + m_stack.push_back(_ext.currentBlock.difficulty()); break; case Instruction::GASLIMIT: - m_stack.push_back(_ext.currentBlock.gasLimit); + m_stack.push_back(_ext.currentBlock.gasLimit()); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libtestutils/BlockChainLoader.cpp b/libtestutils/BlockChainLoader.cpp index e6c47e2fe..7e08243af 100644 --- a/libtestutils/BlockChainLoader.cpp +++ b/libtestutils/BlockChainLoader.cpp @@ -36,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) // load genesisBlock m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); - assert(m_state.rootHash() == m_bc->info().stateRoot); + assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks for (auto const& block: _json["blocks"]) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 15d39bded..fae12708c 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -88,18 +88,18 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) if (_bi) { res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["parentHash"] = toJS(_bi.parentHash()); + res["sha3Uncles"] = toJS(_bi.sha3Uncles()); + res["miner"] = toJS(_bi.coinbaseAddress()); + res["stateRoot"] = toJS(_bi.stateRoot()); + res["transactionsRoot"] = toJS(_bi.transactionsRoot()); res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); + res["number"] = toJS(_bi.number()); res["gasUsed"] = toJS(_bi.gasUsed); res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["logsBloom"] = toJS(_bi.logBloom); + res["timestamp"] = toJS(_bi.timestamp()); + res["extraData"] = toJS(_bi.extraData()); + res["logsBloom"] = toJS(_bi.logBloom()); res["target"] = toJS(_bi.boundary()); // TODO: move into ProofOfWork. @@ -140,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number())); } return res; } @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()); + res["stateRoot"] = toJS(_t.stateRoot()()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b43c4db51..bae980a7e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -151,12 +151,12 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); m_environment.currentBlock.number = toInt(_o["currentNumber"]); m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 9ee93779e..7dbc5c91e 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(blocks) u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString()); h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString())); h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); - ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom); - ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress); + ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); + ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), - _blockInfo.extraData.begin(), - _blockInfo.extraData.end() + _blockInfo.extraData().begin(), + _blockInfo.extraData().end() ); ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); @@ -132,11 +132,11 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); - ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp); - ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles); + ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); + ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; BlockInfo blockInfo = _client.blockInfo(blockHash); diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 20f60618f..cf44dfd9f 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -66,7 +66,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,9 +76,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot = trueState.rootHash(); + biGenesisBlock.stateRoot() = trueState.rootHash(); else - TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -125,7 +125,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TransientDirectory td_stateDB, td_bc; BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -225,7 +225,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); updatePoW(current_BlockHeader); } @@ -302,7 +302,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (o.count("expect") > 0) { stateOptionsMap expectStateMap; - State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); @@ -313,7 +313,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section - State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); }//_fillin @@ -374,19 +374,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); @@ -551,7 +551,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp = (u256)time(0); + uncleBlockFromFields.timestamp() = (u256)time(0); cnote << "uncle block n = " << toString(uncleBlockFromFields.number); if (_vBiBlocks.size() > 2) { @@ -568,15 +568,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash; - uncleBlockFromFields.stateRoot = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot; + uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); + uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); if (overwrite == "timestamp") { - uncleBlockFromFields.timestamp = toInt(uncleHeaderObj["timestamp"]); + uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); } } @@ -660,19 +660,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { BlockInfo tmp = _header; if (ho.count("parentHash")) - tmp.parentHash = h256(ho["parentHash"].get_str()); + tmp.parentHash() = h256(ho["parentHash"].get_str()); if (ho.count("uncleHash")) - tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); if (ho.count("coinbase")) - tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); if (ho.count("stateRoot")) - tmp.stateRoot = h256(ho["stateRoot"].get_str()); + tmp.stateRoot() = h256(ho["stateRoot"].get_str()); if (ho.count("transactionsTrie")) - tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); if (ho.count("receiptTrie")) - tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); if (ho.count("bloom")) - tmp.logBloom = LogBloom(ho["bloom"].get_str()); + tmp.logBloom() = LogBloom(ho["bloom"].get_str()); if (ho.count("difficulty")) tmp.difficulty = toInt(ho["difficulty"]); if (ho.count("number")) @@ -682,9 +682,9 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) if (ho.count("gasUsed")) tmp.gasUsed = toInt(ho["gasUsed"]); if (ho.count("timestamp")) - tmp.timestamp = toInt(ho["timestamp"]); + tmp.timestamp() = toInt(ho["timestamp"]); if (ho.count("extraData")) - tmp.extraData = importByteArray(ho["extraData"].get_str()); + tmp.extraData() = importByteArray(ho["extraData"].get_str()); // find new valid nonce if (tmp != _header && tmp.difficulty) @@ -751,19 +751,19 @@ mArray writeTransactionsToJson(Transactions const& txs) mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) { - _o["parentHash"] = toString(_bi.parentHash); - _o["uncleHash"] = toString(_bi.sha3Uncles); - _o["coinbase"] = toString(_bi.coinbaseAddress); - _o["stateRoot"] = toString(_bi.stateRoot); - _o["transactionsTrie"] = toString(_bi.transactionsRoot); - _o["receiptTrie"] = toString(_bi.receiptsRoot); - _o["bloom"] = toString(_bi.logBloom); + _o["parentHash"] = toString(_bi.parentHash()); + _o["uncleHash"] = toString(_bi.sha3Uncles()); + _o["coinbase"] = toString(_bi.coinbaseAddress()); + _o["stateRoot"] = toString(_bi.stateRoot()); + _o["transactionsTrie"] = toString(_bi.transactionsRoot()); + _o["receiptTrie"] = toString(_bi.receiptsRoot()); + _o["bloom"] = toString(_bi.logBloom()); _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); - _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); + _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); _o["hash"] = toString(_bi.hash()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 02ff4517a..2d5a2faa6 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index fdfb180fb..28b2e43ab 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -83,10 +83,10 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st mObject FakeExtVM::exportEnv() { mObject ret; - ret["previousHash"] = toString(currentBlock.parentHash); + ret["previousHash"] = toString(currentBlock.parentHash()); ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); - ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp, HexPrefix::Add, 1); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); return ret; @@ -102,13 +102,13 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash = h256(_o["previousHash"].get_str()); + currentBlock.parentHash() = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } mObject FakeExtVM::exportState() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d44545145..4a6507cd6 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1188,7 +1188,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " return block.timestamp() == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/third/MainWin.cpp b/third/MainWin.cpp index f2a90cc0b..a3b05572f 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From a787e833f580177cd0f7fd7879a3505712608dee Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:34:11 +0200 Subject: [PATCH 055/113] Minor fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ec37302a2..357926d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -98,7 +98,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + bc().rescue(m_stateDB); m_gp->update(bc()); From 438d8882ae0e2421f510545e394a1cfc9cfd08e8 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 11:43:23 +0200 Subject: [PATCH 056/113] fixed build --- evmjit/libevmjit-cpp/JitVM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 4e1fb66ea..d96da87c1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -42,10 +42,10 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); - m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); - m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); - m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); + m_data.difficulty = eth2jit(_ext.currentBlock.difficulty()); + m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit()); + m_data.number = static_cast(_ext.currentBlock.number()); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); From 1bb6bb5ff2169eaf6cf5336a38a1efc12211ce8d Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 16:45:23 +0200 Subject: [PATCH 057/113] mix working --- CMakeLists.txt | 28 +++++++------- alethzero/MainWin.cpp | 53 ++++++++++++++------------- alethzero/MiningView.cpp | 4 +- alethzero/MiningView.h | 4 +- exp/CMakeLists.txt | 4 +- libethereum/BlockChain.cpp | 1 - libtestutils/BlockChainLoader.cpp | 3 +- libtestutils/StateLoader.cpp | 2 +- libtestutils/StateLoader.h | 2 + libweb3jsonrpc/JsonHelper.cpp | 8 ++-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libwebthree/WebThree.cpp | 2 +- mix/ClientModel.cpp | 4 +- mix/MixClient.cpp | 36 +++++++++--------- mix/MixClient.h | 36 +++++++++++++++--- 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3efc5bad9..b926ae165 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) -# add_subdirectory(libweb3jsonrpc) + add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) -# add_subdirectory(libjsengine) -# add_subdirectory(libjsconsole) -# add_subdirectory(ethconsole) + add_subdirectory(libjsengine) + add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -434,31 +434,31 @@ add_subdirectory(libethcore) if (GENERAL) add_subdirectory(libevm) add_subdirectory(libethereum) -# add_subdirectory(libwebthree) + add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) -# add_subdirectory(ethminer) + add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) -# add_subdirectory(ethkey) + add_subdirectory(ethkey) endif () if (TESTS) -# add_subdirectory(libtestutils) -# add_subdirectory(test) + add_subdirectory(libtestutils) + add_subdirectory(test) if (JSONRPC) -# add_subdirectory(ethrpctest) + add_subdirectory(ethrpctest) endif () endif () if (TOOLS) -# add_subdirectory(rlp) -# add_subdirectory(abi) -# add_subdirectory(ethvm) -# add_subdirectory(eth) + add_subdirectory(rlp) + add_subdirectory(abi) + add_subdirectory(ethvm) + add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ad8f5528c..181772ddb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,9 +189,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; - auto block = CanonBlockChain::createGenesisBlock(); - cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl; @@ -208,13 +208,14 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); @@ -1124,7 +1125,7 @@ void Main::refreshMining() QString t; if (gp.first != EthashAux::NotGenerating) t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second); - MiningProgress p = ethereum()->miningProgress(); + WorkingProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining")); if (ethereum()->isMining() && p.hashes > 0) { @@ -1629,7 +1630,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1699,7 +1700,7 @@ void Main::on_blocks_currentItemChanged() auto details = ethereum()->blockChain().details(h); auto blockData = ethereum()->blockChain().block(h); auto block = RLP(blockData); - BlockInfo info(blockData); + Ethash::BlockHeader info(blockData); stringstream s; @@ -1709,21 +1710,21 @@ void Main::on_blocks_currentItemChanged() time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; - s << "

#" << info.number; + s << "

#" << info.number(); s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
"; s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; - s << "
Mix hash: " << info.mixHash << "" << "
"; - s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; - s << "
Difficulty: " << info.difficulty << "" << "
"; - if (info.number) + s << "
Mix hash: " << info.mixHash() << "" << "
"; + s << "
Nonce: " << info.nonce() << "" << "
"; + s << "
Hash w/o nonce: " << info.hashWithout() << "" << "
"; + s << "
Difficulty: " << info.difficulty() << "" << "
"; + if (info.number()) { - auto e = EthashAux::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce()); + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash() << "" << "
"; } else @@ -1740,19 +1741,19 @@ void Main::on_blocks_currentItemChanged() s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { - BlockInfo uncle = BlockInfo::fromHeader(u.data()); + Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; s << line << "Parent: " << uncle.parentHash() << "" << ""; - s << line << "Number: " << uncle.number << "" << ""; + s << line << "Number: " << uncle.number() << "" << ""; s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; - s << line << "Mix hash: " << uncle.mixHash << "" << ""; - s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Mix hash: " << uncle.mixHash() << "" << ""; + s << line << "Nonce: " << uncle.nonce() << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; - s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = EthashAux::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; + s << line << "Difficulty: " << uncle.difficulty() << "" << ""; + auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce()); + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash()) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; @@ -1764,7 +1765,7 @@ void Main::on_blocks_currentItemChanged() unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } s << "
Post: " << info.stateRoot() << "" << "
"; @@ -1807,7 +1808,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index e020408ea..fb9de0346 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MiningProgress; +using dev::eth::WorkingProgress; // functions using dev::toString; @@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MiningProgress const& _p) +void MiningView::appendStats(list const& _i, WorkingProgress const& _p) { (void)_p; if (_i.empty()) diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 65b9f2ec9..ae81a7cc4 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); + void appendStats(std::list const& _l, dev::eth::WorkingProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MiningProgress m_progress; + dev::eth::WorkingProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 5f876a69b..a9bc09db7 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,10 +18,10 @@ if (READLINE_FOUND) endif() if (JSONRPC) -# target_link_libraries(${EXECUTABLE} web3jsonrpc) + target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -#target_link_libraries(${EXECUTABLE} webthree) +target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b696c77bd..03ab1b46a 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -137,7 +137,6 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map #include "BlockChainLoader.h" #include "StateLoader.h" #include "Common.h" @@ -35,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) m_state = sl.state(); // load genesisBlock - m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); + m_bc.reset(new FullBlockChain(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill)); assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks diff --git a/libtestutils/StateLoader.cpp b/libtestutils/StateLoader.cpp index 235f1c573..cd5c37e96 100644 --- a/libtestutils/StateLoader.cpp +++ b/libtestutils/StateLoader.cpp @@ -27,7 +27,7 @@ using namespace dev::eth; using namespace dev::test; StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): - m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty) + m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty) { for (string const& name: _json.getMemberNames()) { diff --git a/libtestutils/StateLoader.h b/libtestutils/StateLoader.h index 47eb26900..c66f53148 100644 --- a/libtestutils/StateLoader.h +++ b/libtestutils/StateLoader.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace dev { @@ -38,6 +39,7 @@ class StateLoader public: StateLoader(Json::Value const& _json, std::string const& _dbPath); eth::State const& state() const { return m_state; } + eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; } private: eth::State m_state; diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index fae12708c..54fde52e8 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -93,10 +93,10 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["miner"] = toJS(_bi.coinbaseAddress()); res["stateRoot"] = toJS(_bi.stateRoot()); res["transactionsRoot"] = toJS(_bi.transactionsRoot()); - res["difficulty"] = toJS(_bi.difficulty); + res["difficulty"] = toJS(_bi.difficulty()); res["number"] = toJS(_bi.number()); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); + res["gasUsed"] = toJS(_bi.gasUsed()); + res["gasLimit"] = toJS(_bi.gasLimit()); res["timestamp"] = toJS(_bi.timestamp()); res["extraData"] = toJS(_bi.extraData()); res["logsBloom"] = toJS(_bi.logBloom()); @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()()); + res["stateRoot"] = toJS(_t.stateRoot()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 3aff9cf23..bf49d3322 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str return true; } -dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +dev::eth::BlockChain const& WebThreeStubServer::bc() const { return m_web3.ethereum()->blockChain(); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4d545c90e..2860f852b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -34,7 +34,7 @@ namespace eth { class KeyManager; class TrivialGasPricer; -class CanonBlockChain; +class BlockChain; class BlockQueue; } @@ -89,7 +89,7 @@ private: private: h256 blockHash(std::string const& _blockNumberOrHash) const; - dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockChain const& bc() const; dev::eth::BlockQueue const& bq() const; dev::WebThreeDirect& m_web3; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 3c1dea40f..7889b5935 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect( Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) { - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); + m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr(), _dbPath, _we, 0)); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 90ff19feb..5c5f2f4cd 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); stringstream strGas; - strGas << blockInfo.gasUsed; + strGas << blockInfo.gasUsed(); stringstream strNumber; - strNumber << blockInfo.number; + strNumber << blockInfo.number(); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ea4686601..eef6ad6ec 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -24,12 +24,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include "Exceptions.h" using namespace std; @@ -45,22 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho namespace { +} -struct MixPow //dummy POW +MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot): + FullBlockChain(createGenesisBlock(_stateRoot), std::unordered_map(), _path, WithExisting::Kill) { - typedef int Solution; - static bool verify(BlockInfo const&) { return true; } -}; - } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(15) + block.appendList(13) << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); + << std::string(); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -78,7 +77,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,12 +89,13 @@ void MixClient::resetState(std::unordered_map const& _accounts SecureTrieDB accountState(&m_stateDB); accountState.init(); - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + dev::eth::commit(_accounts, accountState); h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); + State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + s.sync(bc()); + m_state = s; m_startState = m_state; WriteGuard lx(x_executions); m_executions.clear(); @@ -275,11 +274,14 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + + NoProof::BlockHeader h(m_state.info()); + RLPStream header; + h.streamRLP(header); + m_state.sealBlock(header.out()); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; } ExecutionResult MixClient::lastExecution() const @@ -383,9 +385,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MiningProgress MixClient::miningProgress() const +eth::WorkingProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::WorkingProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..279692de5 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,13 +33,40 @@ namespace dev { + namespace mix { -class MixBlockChain: public dev::eth::BlockChain +class NoProof +{ + class BlockHeaderRaw: public dev::eth::BlockInfo + { + public: + static const unsigned SealFields = 0; + + protected: + BlockHeaderRaw() = default; + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; } + void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; } + void streamRLPFields(RLPStream& _s) const { (void) _s; } + }; + +public: + + static std::string name() { return "NoProof"; } + static unsigned revision() { return 0; } + using BlockHeader = dev::eth::BlockHeaderPolished; + +private: + static AddressHash s_authorities; +}; + +class MixBlockChain: public dev::eth::FullBlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {} + MixBlockChain(std::string const& _path, h256 _stateRoot); static bytes createGenesisBlock(h256 _stateRoot); }; @@ -67,9 +95,7 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MiningProgress miningProgress() const override; - eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } - bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } + eth::WorkingProgress miningProgress() const override; virtual void flushTransactions() override {} /// @returns the last mined block information From 5d2a36ee0f1ba5ea75257988e3a820923f1f9221 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 18:11:08 +0200 Subject: [PATCH 058/113] started tests refactoring --- libethcore/Common.h | 3 ++- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 9 +++++---- libethereum/BlockQueue.cpp | 2 +- libethereum/Client.cpp | 3 +-- mix/MixClient.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libethcore/dagger.cpp | 4 ++-- test/libethereum/ClientBase.cpp | 14 +++++++------- test/libethereum/genesis.cpp | 6 +++--- test/libethereum/stateOriginal.cpp | 5 +++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 5c0a0cc79..116e1d5ed 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -130,9 +130,10 @@ struct ImportRequirements TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, None = 0 }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 03ab1b46a..8a654fa51 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 3ff85c8a6..811da8609 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -118,12 +118,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -391,7 +391,8 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash())); + if ((_ir & ImportRequirements::Parent) != 0) + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c9ee4c1cf..d0ca34b1c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); } catch (...) { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 357926d03..d43f240b7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -84,10 +84,9 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database // until after the construction. m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); - m_preMine = State(m_stateDB); - m_postMine = State(m_stateDB); // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. m_preMine = bc().genesisState(m_stateDB); + m_postMine = m_preMine; m_bq.setChain(bc()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index eef6ad6ec..67f2a2507 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -279,7 +279,7 @@ void MixClient::mine() RLPStream header; h.streamRLP(header); m_state.sealBlock(header.out()); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bae980a7e..30f323369 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,7 +63,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 061b5ae79..8d4cba933 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); - BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); + BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); BOOST_REQUIRE_EQUAL(nonce, header.nonce); unsigned cacheSize(o["cache_size"].get_int()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 7dbc5c91e..a426ff53f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -119,21 +119,21 @@ BOOST_AUTO_TEST_CASE(blocks) h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); - ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); + ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty()); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), _blockInfo.extraData().begin(), _blockInfo.extraData().end() ); - ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); - ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); + ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit()); + ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed()); ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash()); - ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); - ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); - ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); + ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash()); + ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce()); + ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number()); ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 2d5a2faa6..39997572f 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,9 +60,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e3f8ac29f..163c89e50 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ BOOST_AUTO_TEST_CASE(Complex) Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; + OverlayDB stateDB = State::openDB(h256()); + CanonBlockChain bc; cout << bc; State s = bc.genesisState(stateDB); From 8de4926f7496f110229bc2133ebb19ea71ddbe98 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 20:53:58 +0200 Subject: [PATCH 059/113] eth working --- eth/main.cpp | 2 +- ethminer/MinerAux.h | 26 ++++++++++++-------------- libethcore/BlockInfo.h | 1 + libethereum/Client.h | 6 +++++- test/TestHelper.cpp | 17 ++++++++++++----- test/libethcore/dagger.cpp | 6 +++--- test/libethereum/ClientBase.cpp | 4 ++-- test/libethereum/gaspricer.cpp | 3 ++- test/libevm/vm.cpp | 10 +++++----- 9 files changed, 43 insertions(+), 32 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 7ce4d49c2..0b83c97b4 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1310,7 +1310,7 @@ int main(int argc, char** argv) { try { - CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); } catch (...) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 0d227b1ef..01083012f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -397,17 +397,16 @@ public: private: void doInitDAG(unsigned _n) { - BlockInfo bi; - bi.number() = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; - Ethash::prep(bi); + h256 seedHash = EthashAux::seedHash(_n); + cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl; + EthashAux::full(seedHash, true); exit(0); } void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) { - BlockInfo genesis; - genesis.difficulty = 1 << 18; + Ethash::BlockHeader genesis; + genesis.setDifficulty(1 << 18); cdebug << genesis.boundary(); GenericFarm f; @@ -417,17 +416,16 @@ private: cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; - Ethash::prep(genesis); + genesis.prep(); - genesis.difficulty = u256(1) << 63; - genesis.noteDirty(); + genesis.setDifficulty(u256(1) << 63); f.setWork(genesis); if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); - map results; + map results; uint64_t mean = 0; uint64_t innerMean = 0; for (unsigned i = 0; i <= _trials; ++i) @@ -488,9 +486,9 @@ private: Farm rpc(client); GenericFarm f; if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 67a5397f4..c310b3dd9 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -128,6 +128,7 @@ public: void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } Address const& coinbaseAddress() const { return m_coinbaseAddress; } h256 const& stateRoot() const { return m_stateRoot; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 73609bd71..4523d324b 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -77,7 +77,7 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); * @brief Main API hub for interfacing with Ethereum. * Not to be used directly - subclass. */ -class Client: public ClientBase, Worker +class Client: public ClientBase, protected Worker { public: /// New-style Constructor. @@ -342,6 +342,8 @@ public: init(_host, _dbPath, _forceAction, _networkId); } + virtual ~SpecialisedClient() { stopWorking(); } + /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } @@ -365,6 +367,8 @@ public: u256 _networkId = 0 ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + virtual ~EthashClient() { stopWorking(); } + /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. virtual std::tuple getEthashWork() override; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 30f323369..c29788b9f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -63,11 +64,17 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + Ethash::BlockHeader header(s.info); + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { - return completed = s.completeMine(sol); + header.m_mixHash = sol.mixHash; + header.m_nonce = sol.nonce; + RLPStream ret; + header.streamRLP(ret); + s.sealBlock(ret); + return true; }); f.setWork(s.info()); f.startCPU(); @@ -77,9 +84,9 @@ void mine(State& s, BlockChain const& _bc) void mine(BlockInfo& _bi) { - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { _bi.proof = sol; return completed = true; diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 8d4cba933..c3cd75b0d 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(basic_test) h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); - BOOST_REQUIRE_EQUAL(nonce, header.nonce); + BOOST_REQUIRE_EQUAL(nonce, header.nonce()); unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - EthashProofOfWork::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header.seedHash(), header.hashWithout(), header.nonce()); BOOST_REQUIRE_EQUAL(r.value, result); - BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); + BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash()); } } diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index a426ff53f..f9d83e9c6 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber); // blockInfo - auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void + auto compareBlockInfos = [](Json::Value const& _b, Ethash::BlockHeader _blockInfo) -> void { LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString())); Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString())); @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - BlockInfo blockInfo = _client.blockInfo(blockHash); + Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index ce49a4a20..050ab2d25 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer) std::shared_ptr gp(new TrivialGasPricer); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); - gp->update(BlockChain(bytes(), TransientDirectory().path(), WithExisting::Kill)); + gp->update(FullBlockChain(bytes(), StateDefinition(), TransientDirectory().path(), WithExisting::Kill)); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 28b2e43ab..badabd70c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number()), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -84,11 +84,11 @@ mObject FakeExtVM::exportEnv() { mObject ret; ret["previousHash"] = toString(currentBlock.parentHash()); - ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); + ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1); ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); - ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); - ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); + ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1); + ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1); return ret; } @@ -107,7 +107,7 @@ void FakeExtVM::importEnv(mObject& _o) lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } From bcc35d67a19877da9ad667f66a9b9e9202cf0eaa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jul 2015 18:59:19 -0700 Subject: [PATCH 060/113] Modularise nonce, mix hash and seed hash. --- alethzero/MainWin.cpp | 4 +-- ethminer/MinerAux.h | 10 +++---- exp/main.cpp | 2 +- libethcore/BlockInfo.cpp | 45 +++++++++++++----------------- libethcore/BlockInfo.h | 26 +++++++++--------- libethcore/Common.cpp | 5 ++-- libethcore/Common.h | 1 + libethcore/Ethash.cpp | 52 ++++++++++++++++++++++++++++------- libethcore/Ethash.h | 16 +++++++++-- libethcore/EthashAux.cpp | 7 ++++- libethcore/EthashAux.h | 2 +- libethcore/ProofOfWork.h | 1 - libethereum/BlockChain.cpp | 8 +++--- libethereum/BlockQueue.cpp | 12 ++++---- libethereum/State.cpp | 8 +++--- libethereum/State.h | 4 +-- libweb3jsonrpc/JsonHelper.cpp | 7 +++-- mix/MixClient.cpp | 1 - test/TestHelper.cpp | 2 +- 19 files changed, 128 insertions(+), 85 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e48b58283..4655240e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1718,7 +1718,7 @@ void Main::on_blocks_currentItemChanged() s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { @@ -1749,7 +1749,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ff28132b1..5c6112743 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -254,17 +254,17 @@ public: bi.difficulty = u256(m); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bi.proof.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; exit(0); } catch (...) @@ -382,7 +382,7 @@ private: { BlockInfo bi; bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/exp/main.cpp b/exp/main.cpp index 88608f8cf..9884bd0e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -197,7 +197,7 @@ int main() bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, bi); + bi.proof = sol; return completed = true; }); f.setWork(bi); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index fec5b4678..c7acd9091 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -26,7 +26,6 @@ #include #include #include "EthashAux.h" -#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -57,22 +56,21 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - mixHash = h256(); - nonce = Nonce(); - m_hash = m_seedHash = h256(); + proof = ProofOfWork::Solution(); + m_proofCache = ProofOfWork::HeaderCache(); + m_hash = h256(); } -h256 const& BlockInfo::seedHash() const +ProofOfWork::HeaderCache const& BlockInfo::proofCache() const { - if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); - return m_seedHash; + ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); + return m_proofCache; } h256 const& BlockInfo::hash() const { if (!m_hash) - m_hash = headerHash(WithNonce); + m_hash = headerHash(WithProof); return m_hash; } @@ -90,20 +88,20 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const return ret; } -h256 BlockInfo::headerHash(IncludeNonce _n) const +h256 BlockInfo::headerHash(IncludeProof _n) const { RLPStream s; streamRLP(s, _n); return sha3(s.out()); } -void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const +void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const { - _s.appendList(_n == WithNonce ? 15 : 13) + _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithNonce) - _s << mixHash << nonce; + if (_n == WithProof) + proof.streamRLP(_s); } h256 BlockInfo::headerHash(bytesConstRef _block) @@ -116,12 +114,12 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); - m_seedHash = h256(); + m_proofCache = ProofOfWork::HeaderCache(); int field = 0; try { - if (_header.itemCount() != 15) + if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); @@ -136,8 +134,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - mixHash = _header[field = 13].toHash(RLP::VeryStrict); - nonce = _header[field = 14].toHash(RLP::VeryStrict); + proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -152,22 +149,18 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ProofOfWork::composeException(ex, *this); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); - ex << errinfo_seedHash(seedHash()); ex << errinfo_target(boundary()); - ex << errinfo_mixHash(mixHash); - Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce); - ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); BOOST_THROW_EXCEPTION(ex); } else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); + ProofOfWork::composeExceptionPre(ex, *this); BOOST_THROW_EXCEPTION(ex); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 79c12ebb4..b77c47c6b 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -24,16 +24,17 @@ #include #include #include "Common.h" +#include "ProofOfWork.h" namespace dev { namespace eth { -enum IncludeNonce +enum IncludeProof { - WithoutNonce = 0, - WithNonce = 1 + WithoutProof = 0, + WithProof = 1 }; enum Strictness @@ -82,8 +83,7 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - h256 mixHash; - Nonce nonce; + typename ProofOfWork::Solution proof; BlockInfo(); explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} @@ -112,14 +112,13 @@ public: gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && extraData == _cmp.extraData && - mixHash == _cmp.mixHash && - nonce == _cmp.nonce; + proof == _cmp.proof; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } void clear(); - void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); } + void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); @@ -130,16 +129,17 @@ public: u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - h256 const& seedHash() const; + ProofOfWork::HeaderCache const& proofCache() const; h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeNonce _n) const; - void streamRLP(RLPStream& _s, IncludeNonce _n) const; + h256 headerHash(IncludeProof _n) const; + void streamRLP(RLPStream& _s, IncludeProof _n) const; private: - mutable h256 m_seedHash; + + mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; @@ -148,7 +148,7 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; + _bi.gasUsed << " " << _bi.timestamp; return _out; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 618703e22..41cd1bba8 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -26,6 +26,7 @@ #include #include "Exceptions.h" #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -112,9 +113,9 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset; string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; - string const c_space = c_border + string(76, ' ') + c_border; + string const c_space = c_border + string(76, ' ') + c_border + EthReset; stringstream ss; ss << c_line << endl; ss << c_space << endl; diff --git a/libethcore/Common.h b/libethcore/Common.h index 296f0d01d..1e0cdc3b1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -189,6 +189,7 @@ struct TransactionSkeleton Address to; u256 value; bytes data; + u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; u256 nonce = UndefinedU256; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9be76926d..6a4a1445f 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -46,6 +46,7 @@ #endif #include "BlockInfo.h" #include "EthashAux.h" +#include "Exceptions.h" using namespace std; using namespace std::chrono; @@ -56,6 +57,26 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); +void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +{ + if (!io_out) + io_out = EthashAux::seedHash((unsigned)_h.number); +} + +void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); + _ex << errinfo_mixHash(_bi.proof.mixHash); + _ex << errinfo_seedHash(_bi.proofCache()); + Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); + _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +} + +void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); +} + std::string Ethash::name() { return "Ethash"; @@ -66,12 +87,23 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) +{ + mixHash = _header[_field].toHash(RLP::VeryStrict); + nonce = _header[++_field].toHash(RLP::VeryStrict); +} + +void Ethash::Solution::streamRLP(RLPStream& io_rlp) const +{ + io_rlp << mixHash << nonce; +} + Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutNonce); - ret.seedHash = _bi.seedHash(); + ret.headerHash = _bi.headerHash(WithoutProof); + ret.seedHash = _bi.proofCache(); return ret; } @@ -84,7 +116,7 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { - EthashAux::full(_header.seedHash(), true, _f); + EthashAux::full(_header.proofCache(), true, _f); } bool Ethash::preVerify(BlockInfo const& _header) @@ -95,9 +127,9 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), + (uint64_t)(u64)_header.proof.nonce, + (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); return ret; @@ -115,7 +147,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -125,9 +157,9 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; + cwarn << "headerHash:" << _header.headerHash(WithoutProof); + cwarn << "nonce:" << _header.proof.nonce; + cwarn << "mixHash:" << _header.proof.mixHash; cwarn << "difficulty:" << _header.difficulty; cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 7ffd887d0..5640152f0 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -28,16 +28,20 @@ #include #include #include "Common.h" -#include "BlockInfo.h" #include "Miner.h" class ethash_cl_miner; namespace dev { + +class RLP; +class RLPStream; + namespace eth { +class BlockInfo; class EthashCLHook; class Ethash @@ -45,8 +49,17 @@ class Ethash public: using Miner = GenericMiner; + using HeaderCache = h256; + static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); + static void composeException(Exception& _ex, BlockInfo& _bi); + static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + struct Solution { + bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } + void populateFromRLP(RLP const& io_rlp, int& io_field); + void streamRLP(RLPStream& io_rlp) const; + static const unsigned Fields = 2; Nonce nonce; h256 mixHash; }; @@ -78,7 +91,6 @@ public: static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } class CPUMiner: public Miner, Worker { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index efb6066f7..db01f3c49 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,6 +200,11 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } +Ethash::Result EthashAux::eval(BlockInfo const& _header) +{ + return eval(_header, _header.proof.nonce); +} + #define DEV_IF_THROWS(X) try { X; } catch (...) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) @@ -252,7 +257,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { - return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); + return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index d5bd60d44..be07f579c 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -78,7 +78,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 764207aef..7b4298047 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -38,7 +38,6 @@ namespace eth * typename Solution * typename CPUMiner * typename GPUMiner - * void assignResult(BlockInfo&, Result) * and a few others. TODO */ using ProofOfWork = Ethash; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 768ed223f..aaafe7ce9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -575,8 +575,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash.abridged() @@ -666,8 +666,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f95a3880e..690fb60ee 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.hash; + bi.proof.mixHash = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.mixHash == work.hash) + if (it->verified.info.proof.mixHash == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.mixHash == work.hash) + if (i.verified.info.proof.mixHash == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..bf55a50ff 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -837,7 +837,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); + m_currentBlock.streamRLP(block, WithProof); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -902,7 +902,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithNonce); + ubi.streamRLP(unclesData, WithProof); ++unclesCount; uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) @@ -970,7 +970,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithNonce); + m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -978,7 +978,7 @@ void State::completeMine() cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.nonce.abridged(), + m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() ); diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..0555b6dcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -169,11 +169,11 @@ public: if (!m_committedToMine) return false; - PoW::assignResult(_result, m_currentBlock); + m_currentBlock.proof = _result; if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..f7c09ebc2 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -99,11 +99,12 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["gasLimit"] = toJS(_bi.gasLimit); res["timestamp"] = toJS(_bi.timestamp); res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); res["logsBloom"] = toJS(_bi.logBloom); - - res["seedHash"] = toJS(_bi.seedHash()); res["target"] = toJS(_bi.boundary()); + + // TODO: move into ProofOfWork. + res["nonce"] = toJS(_bi.proof.nonce); + res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 8373c7c51..ea4686601 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -49,7 +49,6 @@ namespace struct MixPow //dummy POW { typedef int Solution; - static void assignResult(int, BlockInfo const&) {} static bool verify(BlockInfo const&) { return true; } }; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f49ed1e09..b43c4db51 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(BlockInfo& _bi) bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, _bi); + _bi.proof = sol; return completed = true; }); f.setWork(_bi); From 1bc77af041c96b2fc7f1734c59a2ea10dff5f3e6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 13:03:52 -0700 Subject: [PATCH 061/113] Basic Proof-of-Authority sealent. --- eth/main.cpp | 3 + ethminer/MinerAux.h | 28 +++++++-- libdevcrypto/Common.cpp | 5 ++ libdevcrypto/Common.h | 3 + libethcore/Common.cpp | 4 ++ libethcore/Common.h | 13 +++- libethcore/Ethash.cpp | 26 +++++++- libethcore/Ethash.h | 31 +++++++++ libethcore/EthashAux.cpp | 11 ++++ libethcore/EthashAux.h | 1 + libethcore/Farm.h | 1 - libethcore/Miner.h | 11 ---- libethcore/ProofOfWork.cpp | 25 ++++++++ libethcore/ProofOfWork.h | 76 ++++++++++++++++++++++- libethereum/BlockChain.cpp | 4 ++ libethereum/BlockQueue.cpp | 12 ++-- libethereum/Client.cpp | 15 +---- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 +- libethereum/State.h | 2 +- libweb3jsonrpc/JsonHelper.cpp | 2 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 10 ++- 22 files changed, 246 insertions(+), 43 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 5b38f2779..434860f59 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1700,7 +1700,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) { From 3146cf6cb7212042836ac91b9455f8c248e1e142 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH 062/113] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + 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 BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + 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 BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - 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); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) 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)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); - _ex << errinfo_mixHash(_bi.proof.mixHash); - _ex << errinfo_seedHash(_bi.proofCache()); - Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); - _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); -#else - (void)_ex; - (void)_bi; -#endif -} - -void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) -{ -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); -#else - (void)_ex; - (void)_bi; -#endif -} - -std::string Ethash::name() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) -{ - WorkPackage ret; - ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutProof); -#if ETH_USING_ETHASH - ret.seedHash = _bi.proofCache(); -#endif - return ret; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -void Ethash::prep(BlockInfo const& _header, std::function const& _f) -{ -#if ETH_USING_ETHASH - EthashAux::full(_header.proofCache(), true, _f); -#else - (void)_header; - (void)_f; -#endif + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (number >= ETHASH_EPOCH_LENGTH * 2048) return false; -#if ETH_USING_ETHASH - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ bool Ethash::verify(BlockInfo const& _header) } #endif -#if ETH_USING_ETHASH - auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + 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, unsigned, 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 + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - 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, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#else - using GPUMiner = CPUMiner; -#endif /// Default value of the local work size. Also known as workgroup size. static const unsigned defaultLocalWorkSize; /// Default value of the global work size as a multiplier of the local work size static const unsigned defaultGlobalWorkSizeMultiplier; /// Default value of the milliseconds per global work size (per batch) static const unsigned defaultMSPerBatch; - - struct Farm: public eth::GenericFarm - { - public: - strings sealers() const { return { "cpu", "opencl" }; } - void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } - - void sealBlock(BlockInfo const& _bi) - { - setWork(_bi); - if (m_opencl) - startGPU(); - else - startCPU(); - - setWork(_bi); - ensurePrecomputed((unsigned)_bi.number); - } - - void disable() { stop(); } - - private: - bool m_opencl = false; - }; }; } diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) - return true; - m_miners.clear(); - m_miners.reserve(MinerType::instances()); - for (unsigned i = 0; i < MinerType::instances(); ++i) - { - m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); - -bool BasicAuthority::verify(BlockInfo const& _header) -{ - return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; -} - -bool BasicAuthority::preVerify(BlockInfo const& _header) -{ - return SignatureStruct(_header.proof.sig).isValid(); -} - -BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) -{ - return WorkPackage{_header.headerHash(WithoutProof)}; -} - -void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) -{ - m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); -} - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -class BasicAuthority -{ -public: - struct HeaderCache {}; - static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} - static void composeException(Exception&, BlockInfo&) {} - static void composeExceptionPre(Exception&, BlockInfo&) {} - - struct Solution - { - bool operator==(Solution const& _v) const { return sig == _v.sig; } - void populateFromRLP(RLP const& io_rlp, int& io_field) - { - sig = io_rlp[io_field++].toHash(RLP::VeryStrict); - } - - void streamRLP(RLPStream& io_rlp) const - { - io_rlp << sig; - } - static const unsigned Fields = 1; - Signature sig; - }; - - struct Result - { - Signature sig; - }; - - struct WorkPackage - { - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } - - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - }; - - static const WorkPackage NullWorkPackage; - - static std::string name() { return "BasicAuthority"; } - static unsigned revision() { return 0; } - static void prep(BlockInfo const&, std::function const& = std::function()) {} - static void ensurePrecomputed(unsigned) {} - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - static const Address Authority; - - struct Farm - { - public: - strings sealers() const { return { "default" }; } - void setSealer(std::string const&) {} - void setSecret(Secret const& _s) { m_secret = _s; } - void sealBlock(BlockInfo const& _bi); - void disable() {} - void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } - - private: - Secret m_secret; - std::function m_onSolutionFound; - }; -}; - using ProofOfWork = BasicAuthority; } diff --git a/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + 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 Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + 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 Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady; From fd4486ca796eced8ab994d06e85cfe65148059e6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Jul 2015 16:32:04 -0700 Subject: [PATCH 063/113] Tests working for BasicAuthority and Ethash. --- CMakeLists.txt | 32 ++++++++++++++-------------- exp/CMakeLists.txt | 20 ++++++++++++------ exp/main.cpp | 40 ++++++++++++++++++++++++++--------- libdevcore/Common.h | 1 + libethcore/BasicAuthority.cpp | 18 +++++++++++++--- libethcore/BasicAuthority.h | 7 +++++- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 1 + libethcore/EthashAux.cpp | 23 -------------------- libethcore/EthashAux.h | 2 -- libethcore/Sealer.h | 12 +++++++++++ 12 files changed, 97 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d3c167a..1d35280e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,13 +403,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) - add_subdirectory(libweb3jsonrpc) +# add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) - add_subdirectory(libjsengine) - add_subdirectory(libjsconsole) - add_subdirectory(ethconsole) +# add_subdirectory(libjsengine) +# add_subdirectory(libjsconsole) +# add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -435,33 +435,33 @@ endif () add_subdirectory(libethcore) if (GENERAL) - add_subdirectory(libevm) - add_subdirectory(libethereum) - add_subdirectory(libwebthree) +# add_subdirectory(libevm) +# add_subdirectory(libethereum) +# add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) - add_subdirectory(ethminer) +# add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) - add_subdirectory(ethkey) +# add_subdirectory(ethkey) endif () if (TESTS) - add_subdirectory(libtestutils) - add_subdirectory(test) +# add_subdirectory(libtestutils) +# add_subdirectory(test) if (JSONRPC) - add_subdirectory(ethrpctest) +# add_subdirectory(ethrpctest) endif () endif () if (TOOLS) - add_subdirectory(rlp) - add_subdirectory(abi) - add_subdirectory(ethvm) - add_subdirectory(eth) +# add_subdirectory(rlp) +# add_subdirectory(abi) +# add_subdirectory(ethvm) +# add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 7a80023bf..30f4705f9 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,15 +18,21 @@ if (READLINE_FOUND) endif() if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) +# target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} p2p) +#target_link_libraries(${EXECUTABLE} webthree) +#target_link_libraries(${EXECUTABLE} ethereum) +#target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} ethash) - target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} ethash-cl) +# target_link_libraries(${EXECUTABLE} ethash) +# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) endif() +target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) + + + + + diff --git a/exp/main.cpp b/exp/main.cpp index 07eee6a11..fa8603459 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,6 +70,7 @@ namespace fs = boost::filesystem; #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -80,24 +81,43 @@ using namespace eth; int main() { BlockInfo bi; + bi.difficulty = c_genesisDifficulty; + bi.gasLimit = c_genesisGasLimit; + bi.number = 1; + bi.parentHash = sha3("parentHash"); + bytes sealedData; - SealEngineFace* se = BasicAuthority::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); - se->generateSeal(bi); { + KeyPair kp(sha3("test")); + SealEngineFace* se = BasicAuthority::createSealEngine(); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); + cdebug << se->sealers(); + bool done = false; + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.sig(); } - SealEngineFace* se = Ethash::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); - se->generateSeal(bi); - while (!done) - this_thread::sleep_for(chrono::milliseconds(50)); { + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + bool done = false; + se->setSealer("cpu"); + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.nonce(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 303512e57..612b7c685 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using byte = uint8_t; #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) namespace dev { diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index bbf4e3f2a..7006107e1 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); +AddressHash BasicAuthority::s_authorities; bool BasicAuthority::BlockHeaderRaw::verify() const { - return toAddress(recover(m_sig, hashWithout())) == Authority; + return s_authorities.count(toAddress(recover(m_sig, hashWithout()))); } bool BasicAuthority::BlockHeaderRaw::preVerify() const @@ -94,11 +94,23 @@ public: MiningProgress miningProgress() const { return MiningProgress(); } private: + virtual bool onOptionChanging(std::string const& _name, bytes const& _value) + { + RLP rlp(_value); + if (_name == "authorities") + BasicAuthority::s_authorities = rlp.toUnorderedSet
(); + else if (_name == "authority") + m_secret = rlp.toHash(); + else + return false; + return true; + } + Secret m_secret; std::function m_onSealGenerated; }; -SealEngineFace* createSealEngine() +SealEngineFace* BasicAuthority::createSealEngine() { return new BasicAuthoritySealEngine; } diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 616c18340..9127c1d53 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -30,6 +30,7 @@ #include "Sealer.h" class BasicAuthoritySeal; +class BasicAuthoritySealEngine; namespace dev { @@ -48,6 +49,8 @@ namespace eth */ class BasicAuthority { + friend class ::BasicAuthoritySealEngine; + public: // TODO: remove struct Result {}; @@ -70,6 +73,7 @@ public: Signature sig() const { return m_sig; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 1; @@ -84,7 +88,8 @@ public: }; using BlockHeader = BlockHeaderPolished; - static const Address Authority; +private: + static AddressHash s_authorities; }; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index cd55bc1f6..710279cb2 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -158,7 +158,7 @@ public: explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c3f19e723..d385163be 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -119,7 +119,7 @@ bool Ethash::BlockHeaderRaw::verify() const } #endif - auto result = EthashAux::eval(*this); + auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce); bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); @@ -281,6 +281,7 @@ public: { m_farm.onSolutionFound([=](Ethash::Solution const& sol) { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; EthashSeal s(sol.mixHash, sol.nonce); _f(&s); return true; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index eee0e3881..99baa8a05 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -94,6 +94,7 @@ public: h256 const& mixHash() const { return m_mixHash; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 2; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 42a3cf6fb..00537c21a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,18 +200,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } -Ethash::Result EthashAux::eval(BlockInfo const& _header) -{ -#if ETH_USING_ETHASH - return eval(_header, _header.proof.nonce); -#else - (void)_header; - return Ethash::Result(); -#endif -} - -#define DEV_IF_THROWS(X) try { X; } catch (...) - unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); @@ -260,17 +248,6 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) -{ -#if ETH_USING_ETHASH - return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); -#else - (void)_header; - (void)_nonce; - return Ethash::Result(); -#endif -} - Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 5ae24898d..132b9b436 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -79,8 +79,6 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header); - static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index f491240f3..28381444e 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include "Common.h" namespace dev @@ -43,6 +44,9 @@ public: class SealEngineFace { public: + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; @@ -52,6 +56,14 @@ public: // TODO: rename & generalise virtual bool isMining() const { return false; } virtual MiningProgress miningProgress() const { return MiningProgress(); } + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; }; } From 4f32150a6a3b987ad5a3f96bd19fd7370c3f8d26 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jul 2015 23:24:10 +0200 Subject: [PATCH 064/113] Basic test working with same code for Ethash and BasicAuthority. --- CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 1 - ethminer/MinerAux.h | 17 +-- exp/CMakeLists.txt | 6 +- exp/main.cpp | 86 +++++++------ libdevcore/Guards.h | 29 +++++ libdevcore/RLP.h | 3 + libdevcore/TrieDB.h | 9 +- libethcore/BasicAuthority.cpp | 43 ++++--- libethcore/BasicAuthority.h | 16 +-- libethcore/BlockInfo.cpp | 34 +---- libethcore/BlockInfo.h | 64 ++++++--- libethcore/Common.cpp | 3 +- libethcore/Common.h | 14 +- libethcore/Ethash.cpp | 163 ++++++++++++----------- libethcore/Ethash.h | 52 ++------ libethcore/EthashAux.cpp | 17 ++- libethcore/EthashAux.h | 47 ++++++- libethcore/Farm.h | 6 +- libethcore/Miner.h | 4 +- libethcore/ProofOfWork.cpp | 27 ---- libethcore/ProofOfWork.h | 40 ------ libethcore/Sealer.h | 31 +++-- libethereum/BlockChain.cpp | 136 ++++++++++---------- libethereum/BlockChain.h | 113 ++++++++++++++-- libethereum/BlockChainSync.cpp | 11 +- libethereum/BlockQueue.cpp | 24 ++-- libethereum/BlockQueue.h | 8 +- libethereum/CanonBlockChain.cpp | 75 ++++++----- libethereum/CanonBlockChain.h | 45 ++++++- libethereum/Client.cpp | 200 ++++++++++++++++------------- libethereum/Client.h | 119 +++++++++++------ libethereum/ClientBase.cpp | 2 +- libethereum/ClientBase.h | 4 +- libethereum/Interface.h | 8 +- libethereum/State.cpp | 87 ++++++------- libethereum/State.h | 66 ++++------ libethereum/Utility.cpp | 4 +- libethereum/Utility.h | 3 +- libweb3jsonrpc/JsonHelper.cpp | 6 +- libweb3jsonrpc/JsonHelper.h | 14 ++ test/libethcore/dagger.cpp | 3 +- test/libethereum/stateOriginal.cpp | 3 +- 44 files changed, 933 insertions(+), 716 deletions(-) delete mode 100644 libethcore/ProofOfWork.cpp delete mode 100644 libethcore/ProofOfWork.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d35280e0..b410d875c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,8 +435,8 @@ endif () add_subdirectory(libethcore) if (GENERAL) -# add_subdirectory(libevm) -# add_subdirectory(libethereum) + add_subdirectory(libevm) + add_subdirectory(libethereum) # add_subdirectory(libwebthree) endif () diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4655240e3..2ee8928f5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -208,7 +208,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); diff --git a/eth/main.cpp b/eth/main.cpp index 434860f59..7ce4d49c2 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 051128669..61fde605d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #if ETH_ETHASHCL || !ETH_TRUE @@ -387,7 +386,6 @@ public: #endif } -#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -412,10 +410,10 @@ private: genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - GenericFarm f; - f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + GenericFarm f; + f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); - string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; @@ -488,20 +486,20 @@ private: jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; + GenericFarm f; if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) f.startGPU(); - ProofOfWork::WorkPackage current; + EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; while (true) try { bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) + EthashProofOfWork::Solution solution; + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { solution = sol; return completed = true; @@ -595,5 +593,4 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; -#endif }; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 30f4705f9..5f876a69b 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -22,12 +22,12 @@ if (JSONRPC) endif() #target_link_libraries(${EXECUTABLE} webthree) -#target_link_libraries(${EXECUTABLE} ethereum) -#target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) # target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash) -# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} OpenCL) endif() target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/exp/main.cpp b/exp/main.cpp index fa8603459..4a35068f1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -71,13 +70,16 @@ namespace fs = boost::filesystem; #include #include #include +#include +#include +#include +#include using namespace std; using namespace dev; using namespace eth; #endif -#if 1 - +#if 0 int main() { BlockInfo bi; @@ -124,9 +126,7 @@ int main() return 0; } - #elif 0 - int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); @@ -135,10 +135,7 @@ int main() cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); return 0; } - - #elif 0 - int main() { cdebug << "EXP"; @@ -162,9 +159,7 @@ int main() ret = orderedTrieRoot(data); cdebug << ret; } - #elif 0 - int main() { KeyManager keyman; @@ -186,7 +181,6 @@ int main() cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); } - #elif 0 int main() { @@ -246,15 +240,15 @@ int main() #elif 0 int main() { - GenericFarm f; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { BlockInfo bi = g; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { bi.proof = sol; return completed = true; @@ -289,23 +283,16 @@ int main() return 0; } -#elif 0 - -void mine(State& s, BlockChain const& _bc) +#elif 1 +void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) { s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - return completed = s.completeMine(sol); - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + _se->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); } -#elif 0 int main() { cnote << "Testing State..."; @@ -316,47 +303,62 @@ int main() Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; - cout << bc; + using Sealer = Ethash; + CanonBlockChain bc; + auto gbb = bc.headerData(bc.genesisHash()); + assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData)); + + SealEngineFace* se = Sealer::createSealEngine(); + KeyPair kp(sha3("test")); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); - cout << s; + OverlayDB stateDB = State::openDB(bc.genesisHash()); + cnote << bc; + + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); + cnote << s; // Sync up - this won't do much until we use the last state. s.sync(bc); - cout << s; + cnote << s; // Mine to get some ether! - mine(s, bc); + mine(s, bc, se); - bc.attemptImport(s.blockData(), stateDB); + bytes minedBlock = s.blockData(); + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + bc.import(minedBlock, stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; + cnote << "Miner now has" << s.balance(myMiner.address()); + s.resetCurrent(); + cnote << "Miner now has" << s.balance(myMiner.address()); // Inject a transaction to transfer funds from miner to me. Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); - cout << s; + cnote << s; // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - mine(s, bc); + mine(s, bc, se); bc.attemptImport(s.blockData(), stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; return 0; } diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 44d5969e4..135209d23 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex; using SharedMutex = boost::shared_mutex; using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; using RecursiveGuard = std::lock_guard; using ReadGuard = boost::shared_lock; using UpgradableGuard = boost::upgrade_lock; @@ -74,6 +76,33 @@ private: }; using SpinGuard = std::lock_guard; +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a94c8ba55..701f4b8e8 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -393,6 +393,9 @@ public: /// Read the byte stream. bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + /// Swap the contents of the output stream out for some other byte array. void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..05affa677 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -231,8 +231,11 @@ public: } } -protected: - DB* db() const { return m_db; } + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -383,6 +386,7 @@ public: using Super::isEmpty; using Super::root; + using Super::db; using Super::leftOvers; using Super::check; @@ -435,6 +439,7 @@ public: using Super::check; using Super::open; using Super::setRoot; + using Super::db; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7006107e1..22da67080 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -19,6 +19,7 @@ * @date 2014 */ +#include #include "Exceptions.h" #include "BasicAuthority.h" #include "BlockInfo.h" @@ -60,38 +61,38 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri } } +void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} +void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} -class BasicAuthoritySeal: public SealFace +StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const { -public: - BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + return { { "sig", toJS(m_sig) } }; +} - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - BasicAuthority::BlockHeader h(_bi); - h.m_sig = m_sig; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } -private: - Signature m_sig; -}; -class BasicAuthoritySealEngine: public SealEngineFace +class BasicAuthoritySealEngine: public SealEngineBase { public: void setSecret(Secret const& _s) { m_secret = _s; } void generateSeal(BlockInfo const& _bi) { - BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); - m_onSealGenerated(&s); + BasicAuthority::BlockHeader h(_bi); + h.m_sig = sign(m_secret, _bi.hashWithout()); + RLPStream ret; + h.streamRLP(ret); + m_onSealGenerated(ret.out()); } - void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isWorking() const { return false; } + WorkingProgress workingProgress() const { return WorkingProgress(); } private: virtual bool onOptionChanging(std::string const& _name, bytes const& _value) @@ -107,7 +108,7 @@ private: } Secret m_secret; - std::function m_onSealGenerated; + std::function m_onSealGenerated; }; SealEngineFace* BasicAuthority::createSealEngine() diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 9127c1d53..8db47938b 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -52,33 +52,31 @@ class BasicAuthority friend class ::BasicAuthoritySealEngine; public: - // TODO: remove - struct Result {}; - struct WorkPackage {}; - static const WorkPackage NullWorkPackage; - static std::string name() { return "BasicAuthority"; } static unsigned revision() { return 0; } static SealEngineFace* createSealEngine(); class BlockHeaderRaw: public BlockInfo { - friend class ::BasicAuthoritySeal; + friend class ::BasicAuthoritySealEngine; public: + static const unsigned SealFields = 1; + bool verify() const; bool preVerify() const; - WorkPackage package() const { return NullWorkPackage; } Signature sig() const { return m_sig; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 1; - void populateFromHeader(RLP const& _header, Strictness _s); + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); void streamRLPFields(RLPStream& _s) const { _s << m_sig; } void clear() { m_sig = Signature(); } void noteDirty() const {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb07162fb..64961bc40 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,10 +36,10 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt) { - RLP header = extractHeader(_block); - m_hash = sha3(header.data()); + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); populateFromHeader(header, _s); } @@ -58,7 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - m_hashWithout = h256(); + noteDirty(); } h256 const& BlockInfo::boundary() const @@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing) - { - if (gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); - - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); - - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); - - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); - } + if (_s != CheckNothing && gasUsed > gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) gasLimit = selectGasLimit(_parent); gasUsed = 0; difficulty = calculateDifficulty(_parent); + parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const @@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const void BlockInfo::verifyParent(BlockInfo const& _parent) const { - // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); - - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); - // Check timestamp is after previous timestamp. if (parentHash) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 710279cb2..b00fa73fb 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -42,10 +42,18 @@ enum Strictness { CheckEverything, QuickNonce, - IgnoreNonce, + IgnoreSeal, CheckNothing }; +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); + /** @brief Encapsulation of a block header. * Class to contain all of a block header's data. It is able to parse a block header and populate * from some given RLP block serialisation with the static fromHeader(), through the method @@ -69,7 +77,10 @@ enum Strictness */ struct BlockInfo { + friend class BlockChain; public: + static const unsigned BasicFields = 13; + // TODO: make them all private! h256 parentHash; h256 sha3Uncles; @@ -78,7 +89,7 @@ public: h256 transactionsRoot; h256 receiptsRoot; LogBloom logBloom; - u256 difficulty; + u256 difficulty; // TODO: pull out into BlockHeader u256 number; u256 gasLimit; u256 gasUsed; @@ -86,10 +97,12 @@ public: bytes extraData; BlockInfo(); - BlockInfo(bytesConstRef _block, Strictness _s); + explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); + explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -121,17 +134,14 @@ public: /// sha3 of the header only. h256 const& hashWithout() const; - h256 const& hash() const { return m_hash; } - -protected: - static RLP extractHeader(bytesConstRef _block); - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); - void streamRLPFields(RLPStream& _s) const; + h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } void clear(); void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } - static const unsigned BasicFields = 13; +protected: + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal); + void streamRLPFields(RLPStream& _s) const; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. @@ -152,35 +162,50 @@ template class BlockHeaderPolished: public BlockInfoSub { public: + static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields; + BlockHeaderPolished() {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} - explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } - explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); } + explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); } - static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } + // deprecated - just use constructor instead. + static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } + static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } - void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + // deprecated for public API - use constructor. + // TODO: make private. + void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData) + { + populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h); + } void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); BlockInfo::parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); + BlockInfoSub::populateFromParent(_parent); } + // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); + BlockInfoSub::verifyParent(_parent); } - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + // deprecated for public API - use constructor. + // TODO: make private. + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { BlockInfo::m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); + else + BlockInfo::m_hash = dev::sha3(_header.data()); if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); @@ -213,6 +238,13 @@ public: if (_i == WithProof) BlockInfoSub::streamRLPFields(_s); } + + bytes sealFieldsRLP() const + { + RLPStream s; + BlockInfoSub::streamRLPFields(s); + return s.out(); + } }; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 58e506b37..499854584 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -29,7 +29,6 @@ #include #include #include "Exceptions.h" -#include "ProofOfWork.h" #include "BlockInfo.h" using namespace std; using namespace dev; @@ -57,7 +56,7 @@ Network const c_network = Network::Frontier; Network const c_network = Network::Olympic; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 1a688fbd8..5c0a0cc79 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -124,10 +124,16 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, ///< Validate nonce + ValidSeal = 1, ///< Validate seal DontHave = 2, ///< Avoid old blocks - CheckUncles = 4, ///< Check uncle nonces - Default = ValidNonce | DontHave | CheckUncles + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures + Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + None = 0 }; }; @@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(& /** * @brief Describes the progress of a mining operation. */ -struct MiningProgress +struct WorkingProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index d385163be..128822b80 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "Exceptions.h" #include "Farm.h" #include "Miner.h" +#include "Params.h" using namespace std; using namespace std::chrono; @@ -57,8 +59,6 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); - h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) @@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); ex << errinfo_mixHash(m_mixHash); ex << errinfo_seedHash(seedHash()); - Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); ex << errinfo_difficulty(difficulty); @@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } + + if (_s != CheckNothing) + { + if (difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + + if (gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + + if (number && extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + } +} + +void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + + if (gasLimit < c_minGasLimit || + gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || + gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); +} + +void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; } bool Ethash::BlockHeaderRaw::preVerify() const @@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const return slow; } -Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const -{ - WorkPackage ret; - ret.boundary = boundary(); - ret.headerHash = hashWithout(); - ret.seedHash = seedHash(); - return ret; -} - void Ethash::BlockHeaderRaw::prep(std::function const& _f) const { EthashAux::full(seedHash(), true, _f); } +StringHashMap Ethash::BlockHeaderRaw::jsInfo() const +{ + return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; +} @@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function const& _f) const -class EthashCPUMiner: public GenericMiner, Worker +class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -190,7 +214,7 @@ private: }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker +class EthashGPUMiner: public GenericMiner, Worker { friend class dev::eth::EthashCLHook; @@ -234,66 +258,84 @@ private: }; #endif -class EthashSeal: public SealFace +struct EthashSealEngine: public SealEngineBase { -public: - EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} - - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - Ethash::BlockHeader h(_bi); - h.m_mixHash = m_mixHash; - h.m_nonce = m_nonce; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } - -private: - h256 m_mixHash; - h64 m_nonce; -}; + friend class Ethash; -struct EthashSealEngine: public SealEngineFace -{ public: EthashSealEngine() { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; #if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; #endif m_farm.setSealers(sealers); } - strings sealers() const override { return { "cpu", "opencl" }; } + strings sealers() const override + { + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; + } void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void disable() override { m_farm.stop(); } + void cancelGeneration() override { m_farm.stop(); } void generateSeal(BlockInfo const& _bi) override { - m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); m_farm.start(m_sealer); - m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + m_farm.setWork(m_sealing); // TODO: take out one before or one after... Ethash::ensurePrecomputed((unsigned)_bi.number); } - void onSealGenerated(std::function const& _f) override + void onSealGenerated(std::function const& _f) override { - m_farm.onSolutionFound([=](Ethash::Solution const& sol) + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) { cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - EthashSeal s(sol.mixHash, sol.nonce); - _f(&s); + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); return true; }); } private: bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; }; +void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + // Go via the farm since the handler function object is stored as a local within the Farm's lambda. + // Has the side effect of stopping local workers, which is good, as long as it only does it for + // valid submissions. + static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); +} + +bool Ethash::isWorking(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.isMining(); + return false; +} + +WorkingProgress Ethash::workingProgress(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.miningProgress(); + return WorkingProgress(); +} + SealEngineFace* Ethash::createSealEngine() { return new EthashSealEngine; @@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE -using UniqueGuard = std::unique_lock; - -template -class Notified -{ -public: - Notified() {} - Notified(N const& _v): m_value(_v) {} - Notified(Notified const&) = delete; - Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - - operator N() const { UniqueGuard l(m_mutex); return m_value; } - - void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } - -private: - mutable Mutex m_mutex; - mutable std::condition_variable m_cv; - N m_value; -}; - class EthashCLHook: public ethash_cl_miner::search_hook { public: diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99baa8a05..576621bd4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -53,59 +53,42 @@ public: static unsigned revision(); static SealEngineFace* createSealEngine(); - // TODO: remove or virtualize - struct Solution - { - h64 nonce; - h256 mixHash; - }; - // TODO: make private - struct Result - { - h256 value; - h256 mixHash; - }; - // TODO: virtualise - struct WorkPackage - { - WorkPackage() = default; - - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } + using Nonce = h64; - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; - }; - static const WorkPackage NullWorkPackage; + static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce); + static bool isWorking(SealEngineFace* _engine); + static WorkingProgress workingProgress(SealEngineFace* _engine); class BlockHeaderRaw: public BlockInfo { - friend class EthashSeal; + friend class EthashSealEngine; public: + static const unsigned SealFields = 2; + bool verify() const; bool preVerify() const; void prep(std::function const& _f = std::function()) const; - WorkPackage package() const; h256 const& seedHash() const; - h64 const& nonce() const { return m_nonce; } + Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 2; - void populateFromHeader(RLP const& _header, Strictness _s); - void clear() { m_mixHash = h256(); m_nonce = h64(); } + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); + void clear() { m_mixHash = h256(); m_nonce = Nonce(); } void noteDirty() const { m_seedHash = h256(); } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - h64 m_nonce; + Nonce m_nonce; h256 m_mixHash; mutable h256 m_seedHash; @@ -115,13 +98,6 @@ public: // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); - - /// Default value of the local work size. Also known as workgroup size. - static const unsigned defaultLocalWorkSize; - /// Default value of the global work size as a multiplier of the local work size - static const unsigned defaultGlobalWorkSizeMultiplier; - /// Default value of the milliseconds per global work size (per batch) - static const unsigned defaultMSPerBatch; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 00537c21a..c511978db 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; } EthashAux* dev::eth::EthashAux::s_this = nullptr; +const unsigned EthashProofOfWork::defaultLocalWorkSize = 64; +const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE +const unsigned EthashProofOfWork::defaultMSPerBatch = 0; +const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage(); + EthashAux::~EthashAux() { } @@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; } -Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) if (FullType dag = get()->m_fulls[_seedHash].lock()) return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { - return Ethash::Result{ ~h256(), h256() }; + return EthashProofOfWork::Result{ ~h256(), h256() }; } } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 132b9b436..d42e46d91 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -34,6 +34,47 @@ namespace eth struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; +/// Proof of work definition for Ethash. +struct EthashProofOfWork +{ + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + WorkPackage() = default; + WorkPackage(Ethash::BlockHeader const& _bh): + boundary(_bh.boundary()), + headerHash(_bh.hashWithout()), + seedHash(_bh.seedHash()) + {} + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; +}; + class EthashAux { public: @@ -46,7 +87,7 @@ public: LightAllocation(h256 const& _seedHash); ~LightAllocation(); bytesConstRef data() const; - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; ethash_light_t light; uint64_t size; }; @@ -55,7 +96,7 @@ public: { FullAllocation(ethash_light_t _light, ethash_callback_t _cb); ~FullAllocation(); - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; bytesConstRef data() const; uint64_t size() const { return ethash_full_dag_size(full); } ethash_full_t full; @@ -79,7 +120,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: EthashAux() {} diff --git a/libethcore/Farm.h b/libethcore/Farm.h index b69f8325a..c86b4804e 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -123,9 +123,9 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const + WorkingProgress const& miningProgress() const { - MiningProgress p; + WorkingProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); @@ -195,7 +195,7 @@ private: std::atomic m_isMining = {false}; mutable SharedMutex x_progress; - mutable MiningProgress m_progress; + mutable WorkingProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 03eba9880..90a5902c4 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,9 +36,9 @@ namespace dev namespace eth { -struct MineInfo: public MiningProgress {}; +struct MineInfo: public WorkingProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) +inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p) { _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp deleted file mode 100644 index 843db72c7..000000000 --- a/libethcore/ProofOfWork.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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 ProofOfWork.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "ProofOfWork.h" -#include "BlockInfo.h" -using namespace std; -using namespace dev; -using namespace eth; - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h deleted file mode 100644 index f55c54df6..000000000 --- a/libethcore/ProofOfWork.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 ProofOfWork.h - * @author Gav Wood - * @date 2014 - * - * Determines the PoW algorithm. - */ - -#pragma once - -#include -#include -#include "Common.h" -//#include "Ethash.h" -#include "BasicAuthority.h" - -namespace dev -{ -namespace eth -{ - -using ProofOfWork = BasicAuthority; - -} -} diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index 28381444e..137659dfc 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -25,6 +25,7 @@ #include #include +#include #include "Common.h" namespace dev @@ -34,28 +35,22 @@ namespace eth class BlockInfo; -class SealFace -{ -public: - virtual bool wouldSealHeader(BlockInfo const&) const { return true; } - virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; -}; - class SealEngineFace { public: + virtual std::string name() const = 0; + virtual unsigned revision() const = 0; + virtual unsigned sealFields() const = 0; + virtual bytes sealRLP() const = 0; + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; - virtual void onSealGenerated(std::function const& _f) = 0; - virtual void disable() {} - - // TODO: rename & generalise - virtual bool isMining() const { return false; } - virtual MiningProgress miningProgress() const { return MiningProgress(); } + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} protected: virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } @@ -66,5 +61,15 @@ private: std::unordered_map m_options; }; +template +class SealEngineBase: public SealEngineFace +{ +public: + std::string name() const override { return Sealer::name(); } + unsigned revision() const override { return Sealer::revision(); } + unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; } + bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); } +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 14b13b90d..aae8cbd10 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,12 +35,12 @@ #include #include #include -#include #include #include #include #include "GenesisInfo.h" #include "State.h" +#include "Utility.h" #include "Defaults.h" using namespace std; @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 1 +#define ETH_CATCH 0 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 @@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): + m_genesisState(_genesisState) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit // Initialise with the genesis as the last block on the longest chain. m_genesisBlock = _genesisBlock; m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); + m_genesisState = _genesisState; + + // remove the next line real soon. we don't need to be supporting this forever. + upgradeDatabase(_path, genesisHash()); if (open(_path, _we) != c_minorProtocolVersion) rebuild(_path, _p); @@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); - BlockInfo bi(b); + BlockInfo bi(&b); if (_prepPoW) - Ethash::prep(bi); + Ethash::ensurePrecomputed((unsigned)bi.number); if (bi.parentHash != lastHash) { @@ -351,7 +356,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; @@ -388,7 +393,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad, _ir); + block = verifyBlock(&_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) @@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& auto parentBlock = block(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; - clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); + clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); @@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(_block, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this); for (unsigned i = 0; i < s.pending().size(); ++i) { @@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db) try { cout << "block..." << flush; - BlockInfo bi = info(h); - cout << "details..." << flush; - BlockDetails bd = details(h); + BlockInfo bi(block(h)); + cout << "extras..." << flush; + details(h); cout << "state..." << flush; if (_db.exists(bi.stateRoot)) break; @@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +bytes BlockChain::headerData(h256 const& _hash) const { - VerifiedBlockRef res; - try - { - Strictness strictness = Strictness::CheckEverything; - if (~_ir & ImportRequirements::ValidNonce) - strictness = Strictness::IgnoreNonce; + if (_hash == m_genesisHash) + return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes(); - res.info.populate(_block, strictness); - res.info.verifyInternals(&_block); - } - catch (Exception& ex) { - ex << errinfo_phase(1); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; + ReadGuard l(x_blocks); + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + return BlockInfo::extractHeader(&it->second).data().toBytes(); } - RLP r(_block); - unsigned i = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_uncleIndex(i); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; - } - i = 0; - for (RLP const& tr: r[1]) + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + + if (d.empty()) { - bytesConstRef d = tr.data(); - try - { - res.transactions.push_back(Transaction(d, CheckTransaction::Everything)); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_transactionIndex(i); - ex << errinfo_transaction(d.toBytes()); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; + cwarn << "Couldn't find requested block:" << _hash; + return bytes(); } - res.block = bytesConstRef(&_block); - return res; + + noteUsed(_hash); + + WriteGuard l(x_blocks); + m_blocks[_hash].resize(d.size()); + memcpy(m_blocks[_hash].data(), d.data(), d.size()); + + return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes(); } +State BlockChain::genesisState(OverlayDB const& _db) +{ + State ret(_db, BaseState::Empty); + dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? + ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. + ret.m_previousBlock = BlockInfo(&m_genesisBlock); + return ret; +} + + + + + + + + + + + + + + + + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 638c9c3af..50965f2b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,6 +37,7 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" +#include "State.h" namespace std { @@ -86,6 +87,13 @@ enum { }; using ProgressCallback = std::function; +using StateDefinition = std::unordered_map; + +class VersionChecker +{ +public: + VersionChecker(std::string const& _dbPath, h256 const& _genesisHash); +}; /** * @brief Implements the blockchain database. All data this gives is disk-backed. @@ -94,7 +102,7 @@ using ProgressCallback = std::function; class BlockChain { public: - BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); ~BlockChain(); /// Attempt a database re-open. @@ -120,14 +128,17 @@ public: /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; - /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. - BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); } + /// Get the partial-header of a block (or the most recent mined if none given). Thread-safe. + BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); } BlockInfo info() const { return info(currentHash()); } /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. bytes block(h256 const& _hash) const; bytes block() const { return block(currentHash()); } - bytes oldBlock(h256 const& _hash) const; + + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes headerData(h256 const& _hash) const; + bytes headerData() const { return headerData(currentHash()); } /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. BlockDetails details(h256 const& _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } @@ -264,13 +275,16 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); - /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); - /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } -private: + /// Get a pre-made genesis State object. + State genesisState(OverlayDB const& _db); + + /// Verify block and prepare it for enactment + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + +protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); @@ -345,6 +359,7 @@ private: /// Genesis block info. h256 m_genesisHash; bytes m_genesisBlock; + std::unordered_map m_genesisState; ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; @@ -354,6 +369,88 @@ private: friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; +template +class FullBlockChain: public BlockChain +{ +public: + using BlockHeader = typename Sealer::BlockHeader; + + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path, _we, _p) + {} + + /// Get the header of a block (or the most recent mined if none given). Thread-safe. + typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } + typename Sealer::BlockHeader header() const { return header(currentHash()); } + + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + { + VerifiedBlockRef res; + + try + { + BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); + h.verifyInternals(_block); + h.verifyParent(header(h.parentHash)); + res.info = static_cast(h); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + if (_ir && ImportRequirements::UncleBasic) + for (auto const& uncle: r[2]) + { + try + { + BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + if (_ir && ImportRequirements::TransactionBasic) + for (RLP const& tr: r[1]) + { + bytesConstRef d = tr.data(); + try + { + res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None)); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_transactionIndex(i); + ex << errinfo_transaction(d.toBytes()); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + res.block = bytesConstRef(_block); + return res; + } +}; + std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); } diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 2cf2a7583..a59326b77 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const for (unsigned i = 0; i < itemCount; ++i) { - auto h = BlockInfo::headerHash(_r[i].data()); + auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) + switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; @@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const logNewBlock(h); if (m_state == SyncState::NewBlocks) { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); + BlockInfo bi(_r[i].data()); if (bi.number > maxUnknownNumber) { maxUnknownNumber = bi.number; @@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP con { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); + auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { - switch (host().bq().import(_r[0].data(), host().chain())) + switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b6c548c1f..6b400b236 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); } catch (...) { @@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() } } -ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) +ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. - h256 h = BlockInfo::headerHash(_block); + h256 h = BlockInfo::headerHashFromBlock(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; @@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::AlreadyKnown; } - // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { - // TODO: quick verify - bi.populate(_block); - bi.verifyInternals(_block); + // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer + // VERIFY: populates from the block and checks the block is internally coherent. + bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info; } catch (Exception const& _e) { @@ -218,7 +216,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! - if (_bc.isKnown(h)) + if (m_bc->isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; @@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else @@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; @@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad) return !m_readySet.empty(); } -void BlockQueue::tick(BlockChain const& _bc) +void BlockQueue::tick() { vector> todo; { @@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc) cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) - import(&b.second, _bc); + import(&b.second); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index b9e6f5b3b..97fca7c72 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -76,11 +76,13 @@ public: BlockQueue(); ~BlockQueue(); + void setChain(BlockChain const& _bc) { m_bc = &_bc; } + /// Import a block into the queue. - ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. - void tick(BlockChain const& _bc); + void tick(); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. @@ -138,6 +140,8 @@ private: void updateBad_WITH_LOCK(h256 const& _bad); void drainVerified_WITH_BOTH_LOCKS(); + BlockChain const* m_bc; ///< The blockchain into which our imports go. + mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. h256Hash m_readySet; ///< All blocks ready for chain import. diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 4e6d89243..eee4b98b7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -41,14 +40,44 @@ namespace js = json_spirit; #define ETH_CATCH 1 -std::unordered_map const& dev::eth::genesisState() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); +std::string CanonBlockChain::s_genesisStateJSON; + +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) +{ +} + +bytes CanonBlockChain::createGenesisBlock() +{ + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + SecureTrieDB state(&db); + state.init(); + dev::eth::commit(createGenesisState(), state); + stateRoot = state.root(); + } + + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +unordered_map CanonBlockChain::createGenesisState() { static std::unordered_map s_ret; if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(c_genesisInfo, val); + json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()) { u256 balance; @@ -68,53 +97,29 @@ std::unordered_map const& dev::eth::genesisState() return s_ret; } -// TODO: place Registry in here. - -std::unique_ptr CanonBlockChain::s_genesis; -boost::shared_mutex CanonBlockChain::x_genesis; -Nonce CanonBlockChain::s_nonce(u64(42)); - -bytes CanonBlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - SecureTrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - BlockChain(createGenesisBlock(), _path, _we, _pc) +void CanonBlockChain::setGenesisState(std::string const& _json) { + WriteGuard l(x_genesis); + s_genesisStateJSON = _json; + s_genesis.reset(); } -void CanonBlockChain::setGenesisNonce(Nonce const& _n) +void CanonBlockChain::setGenesisNonce(Nonce const& _n) { WriteGuard l(x_genesis); s_nonce = _n; s_genesis.reset(); } -BlockInfo const& CanonBlockChain::genesis() +Ethash::BlockHeader const& CanonBlockChain::genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); - s_genesis.reset(new BlockInfo); - s_genesis->populate(&gb); + s_genesis.reset(new Ethash::BlockHeader); + s_genesis->populate(&gb, CheckEverything); } return *s_genesis; } diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index c16479f0d..d79926703 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BlockDetails.h" #include "Account.h" @@ -45,7 +46,32 @@ std::unordered_map const& genesisState(); * @threadsafe * @todo Make not memory hog (should actually act as a cache and deallocate old entries). */ -class CanonBlockChain: public BlockChain +template +class CanonBlockChain: public FullBlockChain +{ +public: + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + ~CanonBlockChain() {} + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock() + { + RLPStream block(3); + block.appendList(Sealer::BlockHeader::Fields) + << h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string(); + bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP(); + block.appendRaw(sealFields, Sealer::BlockHeader::SealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); + } +}; + +template <> +class CanonBlockChain: public FullBlockChain { public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} @@ -53,22 +79,35 @@ public: ~CanonBlockChain() {} /// @returns the genesis block header. - static BlockInfo const& genesis(); + static Ethash::BlockHeader const& genesis(); /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static std::unordered_map createGenesisState(); + /// Alter the value of the genesis block's nonce. /// @warning Unless you're very careful, make sure you call this right at the start of the /// program, before anything has had the chance to use this class at all. static void setGenesisNonce(Nonce const& _n); + /// Alter all the genesis block's state by giving a JSON string with account details. + /// @TODO implement. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisState(std::string const&); + + // TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, + private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + static std::unique_ptr s_genesis; static Nonce s_nonce; + static std::string s_genesisStateJSON; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 918480263..ec37302a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -72,47 +72,43 @@ static const Addresses c_canaries = Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph }; -VersionChecker::VersionChecker(string const& _dbPath) +Client::Client(std::shared_ptr _gp): + Worker("eth", 0), + m_gp(_gp ? _gp : make_shared()) { - upgradeDatabase(_dbPath); } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Client(_extNet, make_shared(), _dbPath, _forceAction, _networkId) +void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId) { - startWorking(); -} + // Cannot be opened until after blockchain is open, since BlockChain may upgrade the database. + // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database + // until after the construction. + m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); + m_preMine = State(m_stateDB); + m_postMine = State(m_stateDB); + // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. + m_preMine = bc().genesisState(m_stateDB); -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth", 0), - m_vc(_dbPath), - m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), - m_gp(_gp), - m_stateDB(State::openDB(_dbPath, _forceAction)), - m_preMine(m_stateDB, BaseState::CanonGenesis), - m_postMine(m_stateDB) -{ - if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + m_bq.setChain(bc()); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_sealEngine = shared_ptr(Ethash::createSealEngine()); - m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); + bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_gp->update(m_bc); + if (_forceAction == WithExisting::Rescue) + m_bc.rescue(m_stateDB); + + m_gp->update(bc()); - auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); + auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId)); m_host = host; _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common if (_dbPath.size()) Defaults::setDBPath(_dbPath); doWork(); - startWorking(); } @@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000) this_thread::sleep_for(std::chrono::milliseconds(500)); - return m_bq.import(&_block, bc(), _isSafe); + return m_bq.import(&_block, _isSafe); } tuple Client::syncQueue(unsigned _max) { stopWorking(); - return m_bc.sync(m_bq, m_stateDB, _max); + return bc().sync(m_bq, m_stateDB, _max); } void Client::onBadBlock(Exception& _ex) const @@ -294,7 +290,7 @@ void Client::startedWorking() clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -309,7 +305,7 @@ void Client::doneWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -328,7 +324,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.disable(); + m_sealEngine->cancelGeneration(); { WriteGuard l(x_postMine); @@ -340,10 +336,10 @@ void Client::killChain() m_working = State(); m_stateDB = OverlayDB(); - m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); - m_bc.reopen(Defaults::dbPath(), WithExisting::Kill); + m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); + bc().reopen(Defaults::dbPath(), WithExisting::Kill); - m_preMine = State(m_stateDB, BaseState::CanonGenesis); + m_preMine = bc().genesisState(m_stateDB); m_postMine = State(m_stateDB); } @@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); - auto receipts = m_bc.receipts(_block).receipts; + auto d = bc().info(_block); + auto receipts = bc().receipts(_block).receipts; Guard l(x_filtersWatches); io_changed.insert(ChainChangedFilter); @@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable) startMining(); } -MiningProgress Client::miningProgress() const +bool Client::isMining() const { - if (m_farm.isMining()) - return m_farm.miningProgress(); - return MiningProgress(); + return Ethash::isWorking(m_sealEngine.get()); +} + +WorkingProgress Client::miningProgress() const +{ + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()); + return WorkingProgress(); } uint64_t Client::hashrate() const { - if (m_farm.isMining()) - return m_farm.miningProgress().rate(); + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()).rate(); return 0; } @@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -ProofOfWork::WorkPackage Client::getWork() -{ - // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. - // this will be reset as soon as a new block arrives, allowing more transactions to be processed. - bool oldShould = shouldServeWork(); - m_lastGetWork = chrono::system_clock::now(); - - if (!m_mineOnBadChain && isChainBad()) - return ProofOfWork::WorkPackage(); - - // if this request has made us bother to serve work, prep it now. - if (!oldShould && shouldServeWork()) - onPostStateChanged(); - else - // otherwise, set this to true so that it gets prepped next time. - m_remoteWorking = true; - return ProofOfWork::package(m_miningInfo); -} - -bool Client::submitWork(ProofOfWork::Solution const& _solution) -{ - bytes newBlock; - DEV_WRITE_GUARDED(x_working) - if (!m_working.completeMine(_solution)) - return false; - - DEV_READ_GUARDED(x_working) - { - DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; - newBlock = m_working.blockData(); - } - - // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. - m_bq.import(&newBlock, m_bc, true); - - return true; -} - unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; @@ -553,7 +515,7 @@ void Client::syncBlockQueue() ImportRoute ir; unsigned count; Timer t; - tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); if (count) @@ -577,7 +539,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; DEV_WRITE_GUARDED(x_working) - tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp); if (newPendingReceipts.empty()) return; @@ -590,7 +552,7 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restart mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& h: _ir.deadBlocks) { clog(ClientTrace) << "Dead block:" << h; - for (auto const& t: m_bc.transactions(h)) + for (auto const& t: bc().transactions(h)) { clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, IfDropped::Retry); @@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir) newPreMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + preChanged = newPreMine.sync(bc()); if (preChanged || m_postMine.address() != m_preMine.address()) { @@ -700,7 +662,7 @@ void Client::rejigMining() { clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) - m_working.commitToMine(m_bc, m_extraData); + m_working.commitToMine(bc(), m_extraData); DEV_READ_GUARDED(x_working) { DEV_WRITE_GUARDED(x_postMine) @@ -709,10 +671,10 @@ void Client::rejigMining() } if (m_wouldMine) - m_farm.sealBlock(m_miningInfo); + m_sealEngine->generateSeal(m_miningInfo); } if (!m_wouldMine) - m_farm.disable(); + m_sealEngine->cancelGeneration(); } void Client::noteChanged(h256Hash const& _filters) @@ -768,7 +730,7 @@ void Client::tick() { m_report.ticks++; checkWatchGarbage(); - m_bq.tick(m_bc); + m_bq.tick(); m_lastTick = chrono::system_clock::now(); if (m_report.ticks == 15) clog(ClientTrace) << activityReport(); @@ -792,7 +754,7 @@ void Client::checkWatchGarbage() uninstallWatch(i); // blockchain GC - m_bc.garbageCollect(); + bc().garbageCollect(); m_lastGarbageCollection = chrono::system_clock::now(); } @@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const try { State ret(m_stateDB); - ret.populateFromChain(m_bc, _block); + ret.populateFromChain(bc(), _block); return ret.fromPending(_txi); } catch (Exception& ex) @@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const try { State ret(m_stateDB); - PopulationStatistics s = ret.populateFromChain(m_bc, _block); + PopulationStatistics s = ret.populateFromChain(bc(), _block); if (o_stats) swap(s, *o_stats); return ret; @@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const auto h = m_host.lock(); return h ? h->status() : SyncStatus(); } + +bool Client::submitSealed(bytes const& _header) +{ + DEV_WRITE_GUARDED(x_working) + if (!m_working.sealBlock(_header)) + return false; + + bytes newBlock; + DEV_READ_GUARDED(x_working) + { + DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + newBlock = m_working.blockData(); + } + + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. + return m_bq.import(&newBlock, true) == ImportResult::Success; +} + + + + + + + + + + + + + + +std::tuple EthashClient::getEthashWork() +{ + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); + m_lastGetWork = chrono::system_clock::now(); + + if (!m_mineOnBadChain && isChainBad()) + return std::tuple(); + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; + Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + return std::tuple(bh.boundary(), bh.hashWithout(), bh.seedHash()); +} + +bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce) +{ + Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce); + return true; +} + diff --git a/libethereum/Client.h b/libethereum/Client.h index 9ae7c7e09..73609bd71 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -60,12 +60,6 @@ enum ClientWorkState Deleted }; -class VersionChecker -{ -public: - VersionChecker(std::string const& _dbPath); -}; - struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; @@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); /** * @brief Main API hub for interfacing with Ethereum. + * Not to be used directly - subclass. */ class Client: public ClientBase, Worker { public: /// New-style Constructor. - explicit Client( - p2p::Host* _host, - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); - - explicit Client( - p2p::Host* _host, - std::shared_ptr _gpForAdoption, // pass it in with new. - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); + /// Any final derived class's constructor should make sure they call init(). + explicit Client(std::shared_ptr _gpForAdoption); /// Destructor. virtual ~Client(); @@ -129,7 +112,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. - CanonBlockChain const& blockChain() const { return m_bc; } + BlockChain const& blockChain() const { return bc(); } /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. @@ -176,26 +159,16 @@ public: /// NOT thread-safe void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? - bool isMining() const override { return m_farm.isMining(); } + bool isMining() const override; /// Are we mining now? bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MiningProgress miningProgress() const override; + WorkingProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); - /// Update to the latest transactions and get hash of the current block to be mined minus the - /// nonce (the 'work hash') and the difficulty to be met. - virtual ProofOfWork::WorkPackage getWork() override; - - /** @brief Submit the proof for the proof-of-work. - * @param _s A valid solution. - * @return true if the solution was indeed valid and accepted. - */ - virtual bool submitWork(ProofOfWork::Solution const& _proof) override; - // Debug stuff: DownloadMan const* downloadMan() const; @@ -218,12 +191,20 @@ public: /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } /// Rewind to a prior head. - void rewind(unsigned _n) { m_bc.rewind(_n); } + void rewind(unsigned _n) { bc().rewind(_n); } + /// Rescue the chain. + void rescue() { bc().rescue(m_stateDB); } + /// Get the seal engine. + SealEngineFace* sealEngine() const { return m_sealEngine.get(); } protected: + /// Perform critical setup functions. + /// Must be called in the constructor of the finally derived class. + void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); + /// InterfaceStub methods - virtual BlockChain& bc() override { return m_bc; } - virtual BlockChain const& bc() const override { return m_bc; } + virtual BlockChain& bc() override = 0; + virtual BlockChain const& bc() const override = 0; /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. @@ -245,7 +226,10 @@ protected: /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. void noteChanged(h256Hash const& _filters); -private: + /// Submit + bool submitSealed(bytes const& _s); + +protected: /// Called when Worker is starting. void startedWorking() override; @@ -291,8 +275,6 @@ private: /// @warning May be called from any thread. void onBadBlock(Exception& _ex) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -339,5 +321,64 @@ private: bytes m_extraData; }; +template +class SpecialisedClient: public Client +{ +public: + explicit SpecialisedClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): + Client(_gpForAdoption), + m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }) + { + m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSealGenerated([=](bytes const& header){ + return this->submitSealed(header); + }); + init(_host, _dbPath, _forceAction, _networkId); + } + + /// Get the object representing the current canonical blockchain. + CanonBlockChain const& blockChain() const { return m_bc; } + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } + +protected: + CanonBlockChain m_bc; ///< Maintains block database. +}; + +class EthashClient: public SpecialisedClient +{ +public: + /// Trivial forwarding constructor. + explicit EthashClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + + /// Update to the latest transactions and get hash of the current block to be mined minus the + /// nonce (the 'work hash') and the difficulty to be met. + virtual std::tuple getEthashWork() override; + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ + virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } +}; + } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f463b0195..769880269 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const auto bl = bc().block(_blockHash); RLP b(bl); if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); + return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData); else return BlockInfo(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 82f03def0..874f10548 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -156,9 +156,7 @@ public: virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } - virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } - virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } - virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } + virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 973433af9..213e7fb26 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" @@ -207,12 +207,12 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual ProofOfWork::WorkPackage getWork() = 0; + virtual std::tuple getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); } /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; + virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); } /// Check the progress of the mining. - virtual MiningProgress miningProgress() const = 0; + virtual WorkingProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1656109a9..ee2078a07 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } -OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) +OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; @@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) boost::filesystem::remove_all(path + "/state"); } - path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); + path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); ldb::Options o; @@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("beginning of Genesis construction.", true); - if (_bs == BaseState::CanonGenesis) - { - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); - - paranoia("after DB commit of Genesis construction.", true); - m_previousBlock = CanonBlockChain::genesis(); - } - else - m_previousBlock.clear(); - - resetCurrent(); - - assert(m_state.root() == m_previousBlock.stateRoot); + m_previousBlock.clear(); + m_currentBlock.clear(); +// assert(m_state.root() == m_previousBlock.stateRoot); paranoia("end of normal construction.", true); } @@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip; - bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip, _ir); + BlockInfo bip(_bc.block(bi.parentHash)); + sync(_bc, bi.parentHash, bip); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; - auto vb = BlockChain::verifyBlock(b); + auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); t.restart(); - enact(vb, _bc, _ir); + enact(vb, _bc); ret.enact = t.elapsed(); } else @@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi, _ir); + sync(_bc, _h, bi); } return ret; @@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ void State::commit() { - m_touched += dev::eth::commit(m_cache, m_db, m_state); + m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } @@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) +bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi) { - (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -355,7 +342,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor { cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; - cwarn << "Bailing."; + cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); } m_previousBlock = bi; @@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) { #if ETH_TIMED_ENACTMENTS Timer t; @@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _ir); + auto ret = enact(_block, _bc); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire RLP rlp(_block); cleanup(false); - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal); m_currentBlock = bi; m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); @@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) { DEV_TIMED_FUNCTION_ABOVE(500); @@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = _block.info; m_currentBlock.noteDirty(); + m_currentBlock = _block.info; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } @@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + // IgnoreSeal since it's a VerifiedBlock. + BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; if (!_bc.isKnown(uncle.parentHash)) @@ -829,6 +817,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { + (void)_bc; + /* commitToMine(_bc); // Update difficulty according to timestamp. @@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out(), std::function(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) { cwarn << "Bad block: " << _e.what(); } - +*/ return false; } @@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) for (auto const& u: us) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { - BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithProof); + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); ++unclesCount; - uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) break; } @@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) m_committedToMine = true; } -void State::completeMine() +bool State::sealBlock(bytesConstRef _header) { - cdebug << "Completing mine!"; + if (!m_committedToMine) + return false; + + cdebug << "Sealing block!"; // Got it! // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithProof); + ret.appendRaw(_header); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); - m_currentBlock.noteDirty(); + m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; -/* StructuredLogger::minedNewBlock( + // TODO: move into Sealer + StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.proof.nonce.abridged(), + "", // Can't give the nonce here. "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - );*/ + ); // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. @@ -989,6 +982,8 @@ void State::completeMine() m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; + + return true; } bool State::addressInUse(Address _id) const diff --git a/libethereum/State.h b/libethereum/State.h index f6a8471ea..805215ee5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "Account.h" @@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati enum class BaseState { PreExisting, - Empty, - CanonGenesis + Empty }; enum class Permanence @@ -104,6 +102,7 @@ class State friend class dev::test::ImportTest; friend class dev::test::StateLoader; friend class Executive; + friend class BlockChain; public: /// Default constructor; creates with a blank database prepopulated with the genesis block. @@ -125,7 +124,7 @@ public: ~State(); /// Construct state object from arbitrary point in blockchain. - PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None); /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. @@ -133,8 +132,8 @@ public: Address address() const { return m_ourAddress; } /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. - static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust); - static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } + static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); } OverlayDB const& db() const { return m_db; } OverlayDB& db() { return m_db; } @@ -163,22 +162,20 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. - template - bool completeMine(typename PoW::Solution const& _result) - { - if (!m_committedToMine) - return false; - - m_currentBlock.proof = _result; - if (!PoW::verify(m_currentBlock)) - return false; - -// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - - completeMine(); - - return true; - } + /// TODO: verify it prior to calling this. + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * while (notYetMined) + * { + * // lock + * commitToMine(_blockChain); // will call uncommitToMine if a repeat. + * completeMine(); + * // unlock + * @endcode + */ + bool sealBlock(bytes const& _header) { return sealBlock(&_header); } + bool sealBlock(bytesConstRef _header); /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. @@ -295,11 +292,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); + bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -313,19 +310,6 @@ public: void resetCurrent(); private: - /** Commit to DB and build the final block if the previous call to mine()'s result is completion. - * Typically looks like: - * @code - * while (notYetMined) - * { - * // lock - * commitToMine(_blockChain); // will call uncommitToMine if a repeat. - * completeMine(); - * // unlock - * @endcode - */ - void completeMine(); - /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -340,7 +324,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -386,7 +370,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, SecureTrieDB& _state) { AddressHash ret; for (auto const& i: _cache) @@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, } else { - SecureTrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); @@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, if (i.second.isFreshCode()) { h256 ch = sha3(i.second.code()); - _db.insert(ch, &i.second.code()); + _state.db()->insert(ch, &i.second.code()); s << ch; } else diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index e02012cd5..1b97f82e7 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args) return m_data; } -void dev::eth::upgradeDatabase(std::string const& _basePath) +void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash) { std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath; @@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath) { auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; - auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash; string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(databaseVersion); diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 0dfe8509b..df48269ec 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -42,7 +43,7 @@ namespace eth */ bytes parseData(std::string const& _args); -void upgradeDatabase(std::string const& _basePath); +void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash); } } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 7d63ed165..15d39bded 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); -#if ETH_USING_ETHASH // TODO: move into ProofOfWork. - res["nonce"] = toJS(_bi.proof.nonce); - res["seedHash"] = toJS(_bi.proofCache()); -#endif +// res["nonce"] = toJS(_bi.proof.nonce); +// res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..624a73e54 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. +template +Json::Value toJson(BlockHeaderPolished const& _bh) +{ + Json::Value res; + if (_bh) + { + res = toJson(static_cast(_bh)); + for (auto const& i: _bh.jsInfo()) + res[i.first] = i.second; + } + return res; +} + } namespace shh diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 1743882e5..061b5ae79 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -24,7 +24,6 @@ #include #include "../JsonSpiritHeaders.h" #include -#include #include #include #include "../TestHelper.h" @@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - Ethash::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 452163061..e3f8ac29f 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. From ff2f952184170e4a0ffcef5ddf55452d3082cc64 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:29:03 +0200 Subject: [PATCH 065/113] All fields of BlockInfo now private. --- alethzero/MainWin.cpp | 34 +++--- ethminer/MinerAux.h | 4 +- evmjit/libevmjit-cpp/JitVM.cpp | 6 +- evmjit/libevmjit/RuntimeManager.cpp | 6 +- exp/main.cpp | 6 +- libethcore/BasicAuthority.cpp | 8 +- libethcore/BlockInfo.cpp | 104 ++++++++--------- libethcore/BlockInfo.h | 91 +++++++++------ libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 40 +++---- libethcore/EthashAux.cpp | 2 +- libethereum/BasicGasPricer.cpp | 6 +- libethereum/BlockChain.cpp | 78 +++++-------- libethereum/BlockChain.h | 2 +- libethereum/BlockChainSync.cpp | 6 +- libethereum/BlockQueue.cpp | 50 ++++---- libethereum/Executive.cpp | 10 +- libethereum/State.cpp | 133 +++++++++++----------- libethereum/State.h | 2 +- libevm/ExtVMFace.h | 4 +- libevm/VM.cpp | 10 +- libtestutils/BlockChainLoader.cpp | 2 +- libweb3jsonrpc/JsonHelper.cpp | 22 ++-- test/TestHelper.cpp | 6 +- test/libethereum/ClientBase.cpp | 18 +-- test/libethereum/blockchain.cpp | 78 ++++++------- test/libethereum/genesis.cpp | 2 +- test/libevm/vm.cpp | 12 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- third/MainWin.cpp | 2 +- 30 files changed, 378 insertions(+), 370 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2ee8928f5..ad8f5528c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,7 +189,7 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; @@ -1629,7 +1629,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1706,7 +1706,7 @@ void Main::on_blocks_currentItemChanged() if (item->data(Qt::UserRole + 1).isNull()) { char timestamp[64]; - time_t rawTime = (time_t)(uint64_t)info.timestamp; + time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; s << "

#" << info.number; @@ -1714,7 +1714,7 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; - s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "" << "
"; + s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; @@ -1724,7 +1724,7 @@ void Main::on_blocks_currentItemChanged() { auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; - s << "
Parent: " << info.parentHash << "" << "
"; + s << "
Parent: " << info.parentHash() << "" << "
"; } else { @@ -1732,20 +1732,20 @@ void Main::on_blocks_currentItemChanged() s << "
Parent: It was a virgin birth
"; } // s << "
Bloom: " << details.bloom << ""; - if (!!info.logBloom) - s << "
Log Bloom: " << info.logBloom << "
"; + if (!!info.logBloom()) + s << "
Log Bloom: " << info.logBloom() << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; - s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Parent: " << uncle.parentHash() << "" << ""; s << line << "Number: " << uncle.number << "" << ""; - s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; @@ -1754,20 +1754,20 @@ void Main::on_blocks_currentItemChanged() auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } - if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; + if (info.parentHash()) + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; else s << "
Pre: Nothing is before Phil" << "
"; - s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; + s << "
Receipts: @" << info.receiptsRoot() << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Post: " << info.stateRoot() << "" << "
"; s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } @@ -1807,7 +1807,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 61fde605d..0d227b1ef 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -398,8 +398,8 @@ private: void doInitDAG(unsigned _n) { BlockInfo bi; - bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; + bi.number() = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 2fb2a0e67..4e1fb66ea 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -24,7 +24,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index d48b64bb1..b2c15d7ae 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,7 +1,7 @@ #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" #include "Stack.h" @@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; + case RuntimeData::Timestamp: return "block.timestamp()"; case RuntimeData::Code: return "code.ptr"; case RuntimeData::CodeSize: return "code.size"; } diff --git a/exp/main.cpp b/exp/main.cpp index 4a35068f1..0b740e526 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,8 +85,8 @@ int main() BlockInfo bi; bi.difficulty = c_genesisDifficulty; bi.gasLimit = c_genesisGasLimit; - bi.number = 1; - bi.parentHash = sha3("parentHash"); + bi.number() = 1; + bi.parentHash() = sha3("parentHash"); bytes sealedData; @@ -329,7 +329,7 @@ int main() mine(s, bc, se); bytes minedBlock = s.blockData(); - cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot(); bc.import(minedBlock, stateDB); cnote << bc; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 22da67080..7ef3dd21e 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -44,19 +44,19 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri m_sig = _header[BlockInfo::BasicFields].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); BOOST_THROW_EXCEPTION(ex); } } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 64961bc40..266f57cc8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -BlockInfo::BlockInfo(): timestamp(Invalid256) +BlockInfo::BlockInfo(): m_timestamp(Invalid256) { } @@ -45,26 +45,26 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, void BlockInfo::clear() { - parentHash = h256(); - sha3Uncles = EmptyListSHA3; - coinbaseAddress = Address(); - stateRoot = EmptyTrie; - transactionsRoot = EmptyTrie; - receiptsRoot = EmptyTrie; - logBloom = LogBloom(); - difficulty = 0; - number = 0; - gasLimit = 0; - gasUsed = 0; - timestamp = 0; - extraData.clear(); + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_coinbaseAddress = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = 0; + m_extraData.clear(); noteDirty(); } h256 const& BlockInfo::boundary() const { - if (!m_boundary && difficulty) - m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); + if (!m_boundary && m_difficulty) + m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty); return m_boundary; } @@ -81,8 +81,8 @@ h256 const& BlockInfo::hashWithout() const void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << gasLimit << gasUsed << timestamp << extraData; + _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; } h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) @@ -110,19 +110,19 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { - parentHash = _header[field = 0].toHash(RLP::VeryStrict); - sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); - coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); - stateRoot = _header[field = 3].toHash(RLP::VeryStrict); - transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); - receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); - logBloom = _header[field = 6].toHash(RLP::VeryStrict); - difficulty = _header[field = 7].toInt(); - number = _header[field = 8].toInt(); - gasLimit = _header[field = 9].toInt(); - gasUsed = _header[field = 10].toInt(); - timestamp = _header[field = 11].toInt(); - extraData = _header[field = 12].toBytes(); + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toInt(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toInt(); + m_extraData = _header[field = 12].toBytes(); } catch (Exception const& _e) { @@ -130,11 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) throw; } - if (number > ~(unsigned)0) + if (m_number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing && gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); + if (_s != CheckNothing && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -147,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); - if (transactionsRoot != expectedRoot) + if (m_transactionsRoot != expectedRoot) { MemoryDB tm; GenericTrieDB transactionsTrie(&tm); @@ -172,52 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) cdebug << toHex(t); - BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot)); + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); - if (sha3Uncles != sha3(root[2].data())) + if (m_sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } void BlockInfo::populateFromParent(BlockInfo const& _parent) { - stateRoot = _parent.stateRoot; - number = _parent.number + 1; - gasLimit = selectGasLimit(_parent); - gasUsed = 0; - difficulty = calculateDifficulty(_parent); - parentHash = _parent.hash(); + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_gasLimit = selectGasLimit(_parent); + m_gasUsed = 0; + m_difficulty = calculateDifficulty(_parent); + m_parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return c_genesisGasLimit; else // target minimum of 3141592 - if (_parent.gasLimit < c_genesisGasLimit) - return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + if (_parent.m_gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return (u256)c_genesisDifficulty; else - return max(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor))); + return max(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); } void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check timestamp is after previous timestamp. - if (parentHash) + if (m_parentHash) { - if (timestamp <= _parent.timestamp) + if (m_timestamp <= _parent.m_timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); - if (number != _parent.number + 1) + if (m_number != _parent.m_number + 1) BOOST_THROW_EXCEPTION(InvalidNumber()); } } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b00fa73fb..67a5397f4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -81,21 +81,6 @@ struct BlockInfo public: static const unsigned BasicFields = 13; - // TODO: make them all private! - h256 parentHash; - h256 sha3Uncles; - Address coinbaseAddress; - h256 stateRoot; - h256 transactionsRoot; - h256 receiptsRoot; - LogBloom logBloom; - u256 difficulty; // TODO: pull out into BlockHeader - u256 number; - u256 gasLimit; - u256 gasUsed; - u256 timestamp = Invalid256; - bytes extraData; - BlockInfo(); explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} @@ -104,23 +89,23 @@ public: static h256 headerHashFromBlock(bytesConstRef _block); static RLP extractHeader(bytesConstRef _block); - explicit operator bool() const { return timestamp != Invalid256; } + explicit operator bool() const { return m_timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { - return parentHash == _cmp.parentHash && - sha3Uncles == _cmp.sha3Uncles && - coinbaseAddress == _cmp.coinbaseAddress && - stateRoot == _cmp.stateRoot && - transactionsRoot == _cmp.transactionsRoot && - receiptsRoot == _cmp.receiptsRoot && - logBloom == _cmp.logBloom && - difficulty == _cmp.difficulty && - number == _cmp.number && - gasLimit == _cmp.gasLimit && - gasUsed == _cmp.gasUsed && - timestamp == _cmp.timestamp && - extraData == _cmp.extraData; + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_coinbaseAddress == _cmp.coinbaseAddress() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } @@ -132,6 +117,31 @@ public: u256 selectGasLimit(BlockInfo const& _parent) const; h256 const& boundary() const; + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); } + void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + + Address const& coinbaseAddress() const { return m_coinbaseAddress; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& timestamp() const { return m_timestamp; } + bytes const& extraData() const { return m_extraData; } + + u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader + /// sha3 of the header only. h256 const& hashWithout() const; h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } @@ -145,6 +155,21 @@ protected: mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + h256 m_parentHash; + h256 m_sha3Uncles; + Address m_coinbaseAddress; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + u256 m_number; + u256 m_gasLimit; + u256 m_gasUsed; + u256 m_timestamp = Invalid256; + bytes m_extraData; + + u256 m_difficulty; // TODO: pull out into BlockHeader + private: mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty @@ -152,9 +177,9 @@ private: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp; + _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); return _out; } @@ -191,7 +216,7 @@ public: // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { - if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); BlockInfoSub::verifyParent(_parent); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 499854584..05cc45280 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -124,7 +124,7 @@ static void badBlockInfo(BlockInfo const& _bi, string const& _err) ss << c_space << endl; ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_space << endl; - string bin = toString(_bi.number); + string bin = toString(_bi.number()); ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; ss << c_space << endl; ss << c_line; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 128822b80..ee483aa8b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ namespace eth h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); + m_seedHash = EthashAux::seedHash((unsigned)m_number); return m_seedHash; } @@ -72,7 +72,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_nonce(m_nonce); @@ -81,42 +81,42 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } if (_s != CheckNothing) { - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + if (m_difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) ); - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + if (m_gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) ); - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + if (m_number && m_extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size()))); } } void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) { // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + if (m_difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty)); - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); + if (m_gasLimit < c_minGasLimit || + m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor || + m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)); } void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) @@ -126,7 +126,7 @@ void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) bool Ethash::BlockHeaderRaw::preVerify() const { - if (number >= ETHASH_EPOCH_LENGTH * 2048) + if (m_number >= ETHASH_EPOCH_LENGTH * 2048) return false; bool ret = !!ethash_quick_check_difficulty( @@ -162,7 +162,7 @@ bool Ethash::BlockHeaderRaw::verify() const cwarn << "headerHash:" << hashWithout(); cwarn << "nonce:" << m_nonce; cwarn << "mixHash:" << m_mixHash; - cwarn << "difficulty:" << difficulty; + cwarn << "difficulty:" << m_difficulty; cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; @@ -290,7 +290,7 @@ public: m_farm.setWork(m_sealing); m_farm.start(m_sealer); m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number); + Ethash::ensurePrecomputed((unsigned)_bi.number()); } void onSealGenerated(std::function const& _f) override { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index c511978db..763bea417 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,7 +63,7 @@ EthashAux* EthashAux::get() uint64_t EthashAux::cacheSize(BlockInfo const& _header) { - return ethash_get_cachesize((uint64_t)_header.number); + return ethash_get_cachesize((uint64_t)_header.number()); } uint64_t EthashAux::dataSize(uint64_t _blockNumber) diff --git a/libethereum/BasicGasPricer.cpp b/libethereum/BasicGasPricer.cpp index 145d23594..b957966f8 100644 --- a/libethereum/BasicGasPricer.cpp +++ b/libethereum/BasicGasPricer.cpp @@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; h256 p = _bc.currentHash(); - m_gasPerBlock = _bc.info(p).gasLimit; + m_gasPerBlock = _bc.info(p).gasLimit(); map dist; u256 total = 0; @@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc) while (c < 1000 && p) { BlockInfo bi = _bc.info(p); - if (bi.transactionsRoot != EmptyTrie) + if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); @@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc) i++; } } - p = bi.parentHash; + p = bi.parentHash(); ++c; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aae8cbd10..b696c77bd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) { try { BlockInfo d(bytesConstRef(it->value())); - _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; + _out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; } catch (...) { cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); @@ -293,11 +293,11 @@ void BlockChain::rebuild(std::string const& _path, std::function parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1); + cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); return; } lastHash = bi.hash(); @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -461,21 +461,21 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Work out its number as the parent's number + 1 - if (!isKnown(_block.info.parentHash)) + if (!isKnown(_block.info.parentHash())) { - clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash(); // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_block.info.parentHash); + auto pd = details(_block.info.parentHash()); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_block.info.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; + auto parentBlock = block(_block.info.parentHash()); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash()); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number(); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -483,9 +483,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Check it's not crazy - if (_block.info.timestamp > (u256)time(0)) + if (_block.info.timestamp() > (u256)time(0)) { - clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } @@ -543,9 +543,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_block.info.parentHash); + details(_block.info.parentHash()); DEV_WRITE_GUARDED(x_details) - m_details[_block.info.parentHash].children.push_back(_block.info.hash()); + m_details[_block.info.parentHash()].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); @@ -554,9 +554,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp())); - extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); @@ -585,10 +585,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif - // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; h256 common; @@ -599,7 +599,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash()); route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be @@ -630,15 +630,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Collate logs into blooms. h256s alteredBlooms; { - LogBloom blockBloom = tbi.logBloom; - blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); + LogBloom blockBloom = tbi.logBloom(); + blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref())); // Pre-memoize everything we need before locking x_blocksBlooms - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) blocksBlooms(chunkId(level, index / c_bloomIndexSize)); WriteGuard l(x_blocksBlooms); - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) { unsigned i = index / c_bloomIndexSize; unsigned o = index % c_bloomIndexSize; @@ -661,23 +661,23 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& ReadGuard l1(x_blocksBlooms); for (auto const& h: alteredBlooms) extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); - extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); + extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); } // FINALLY! change our best hash. { newLastBlockHash = _block.info.hash(); - newLastBlockNumber = (unsigned)_block.info.number; + newLastBlockNumber = (unsigned)_block.info.number(); } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; #if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif } @@ -750,7 +750,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& checkBest = t.elapsed(); if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number(); cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; @@ -758,7 +758,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; cnote << " " << _block.transactions.size() << " transactions"; - cnote << " " << _block.info.gasUsed << " gas used"; + cnote << " " << _block.info.gasUsed() << " gas used"; } #endif @@ -861,7 +861,7 @@ void BlockChain::rescue(OverlayDB& _db) cout << "extras..." << flush; details(h); cout << "state..." << flush; - if (_db.exists(bi.stateRoot)) + if (_db.exists(bi.stateRoot())) break; } catch (...) {} @@ -1233,19 +1233,3 @@ State BlockChain::genesisState(OverlayDB const& _db) return ret; } - - - - - - - - - - - - - - - - diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50965f2b6..3ff85c8a6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -391,7 +391,7 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash)); + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index a59326b77..64d1bb197 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr _peer) unsigned BlockChainSync::estimatedHashes() const { BlockInfo block = host().chain().info(); - time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp(); time_t now = time(0); unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) @@ -220,9 +220,9 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); - if (bi.number > maxUnknownNumber) + if (bi.number() > maxUnknownNumber) { - maxUnknownNumber = bi.number; + maxUnknownNumber = bi.number(); maxUnknown = h; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6b400b236..c9ee4c1cf 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,8 +101,8 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.sha3Uncles = work.hash; - bi.parentHash = work.parentHash; + bi.setSha3Uncles(work.hash); + bi.setParentHash(work.parentHash); m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.sha3Uncles == work.hash) + if (it->verified.info.sha3Uncles() == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,11 +136,11 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash) { // we're next! m_verifying.pop_front(); - if (m_knownBad.count(res.verified.info.parentHash)) + if (m_knownBad.count(res.verified.info.parentHash())) { m_readySet.erase(res.verified.info.hash()); m_knownBad.insert(res.verified.info.hash()); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.sha3Uncles == work.hash) + if (i.verified.info.sha3Uncles() == work.hash) { i = move(res); goto OK; @@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() { while (!m_verifying.empty() && !m_verifying.front().blockData.empty()) { - if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + if (m_knownBad.count(m_verifying.front().verified.info.parentHash())) { m_readySet.erase(m_verifying.front().verified.info.hash()); m_knownBad.insert(m_verifying.front().verified.info.hash()); @@ -213,7 +213,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) return ImportResult::Malformed; } - clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash(); // Check block doesn't already exist first! if (m_bc->isKnown(h)) @@ -227,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // Check it's not in the future (void)_isOurs; - if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) + if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/) { - m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); + m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes()))); char buf[24]; - time_t bit = (unsigned)bi.timestamp; + time_t bit = (unsigned)bi.timestamp(); if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails - clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp() << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); + m_difficulty += bi.difficulty(); + bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash()); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. - if (m_knownBad.count(bi.parentHash)) + if (m_knownBad.count(bi.parentHash())) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash())) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; - m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash(); + m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_unknownCount++; return ImportResult::UnknownParent; @@ -268,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash(), _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_knownCount++; noteReady_WITH_LOCK(h); @@ -295,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::vector oldVerified; swap(m_verified, oldVerified); for (auto& b: oldVerified) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash())) { m_knownBad.insert(b.verified.info.hash()); m_readySet.erase(b.verified.info.hash()); @@ -321,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles())) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles(); m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); @@ -460,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; + m_drainingDifficulty += bs.verified.info.difficulty(); m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 866c9c8f9..e58e1a8c6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), + m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)), m_depth(_level) {} @@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction) // Avoid transactions that would take us beyond the block gas limit. u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) + if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit()) { - clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; - BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas())); } // Check gas cost is enough. @@ -403,7 +403,7 @@ void Executive::finalize() m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); - m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); + m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned); // Suicides... if (m_ext) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ee2078a07..64daaf5f8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -105,7 +105,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock.clear(); m_currentBlock.clear(); -// assert(m_state.root() == m_previousBlock.stateRoot); +// assert(m_state.root() == m_previousBlock.stateRoot()); paranoia("end of normal construction.", true); } @@ -123,16 +123,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& auto b = _bc.block(_h); BlockInfo bi(b); - if (bi.number) + if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + BlockInfo bip(_bc.block(bi.parentHash())); + sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. - m_ourAddress = bi.coinbaseAddress; + m_ourAddress = bi.coinbaseAddress(); Timer t; auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); @@ -338,9 +338,9 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - if (m_db.lookup(bi.stateRoot).empty()) + if (m_db.lookup(bi.stateRoot()).empty()) { - cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; + cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); @@ -357,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash()); // push back for later replay. - bi.populate(_bc.block(bi.parentHash)); // move to parent. + bi.populate(_bc.block(bi.parentHash())); // move to parent. } m_previousBlock = bi; @@ -402,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif // Check family: - BlockInfo biParent = _bc.info(_block.info.parentHash); + BlockInfo biParent = _bc.info(_block.info.parentHash()); _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -411,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif BlockInfo biGrandParent; - if (biParent.number) - biGrandParent = _bc.info(biParent.parentHash); + if (biParent.number()) + biGrandParent = _bc.info(biParent.parentHash()); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo()); + sync(_bc, _block.info.parentHash(), BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -462,17 +462,15 @@ void State::resetCurrent() m_cache.clear(); m_touched.clear(); m_currentBlock = BlockInfo(); - m_currentBlock.coinbaseAddress = m_ourAddress; - m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); - m_currentBlock.transactionsRoot = h256(); - m_currentBlock.sha3Uncles = h256(); + m_currentBlock.setCoinbaseAddress(m_ourAddress); + m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0))); m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); m_committedToMine = false; @@ -538,7 +536,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu catch (BlockGasLimitReached const& e) { bigint const& got = *boost::get_error_info(e); - if (got > m_currentBlock.gasLimit) + if (got > m_currentBlock.gasLimit()) { clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; _tq.drop(t.sha3()); @@ -583,7 +581,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number()); string ret; unsigned i = 0; @@ -604,12 +602,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == _block.info.parentHash); - assert(m_currentBlock.parentHash == _block.info.parentHash); - assert(rootHash() == m_previousBlock.stateRoot); + assert(m_previousBlock.hash() == _block.info.parentHash()); + assert(m_currentBlock.parentHash() == _block.info.parentHash()); + assert(rootHash() == m_previousBlock.stateRoot()); #endif - if (m_currentBlock.parentHash != m_previousBlock.hash()) + if (m_currentBlock.parentHash() != m_previousBlock.hash()) // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); @@ -622,7 +620,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) LastHashes lh; DEV_TIMED_ABOVE("lastHashes", 500) - lh = _bc.lastHashes((unsigned)m_previousBlock.number); + lh = _bc.lastHashes((unsigned)m_previousBlock.number()); RLP rlp(_block.block); @@ -651,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) } h256 receiptsRoot; - DEV_TIMED_ABOVE("receiptsRoot", 500) + DEV_TIMED_ABOVE(".receiptsRoot()", 500) receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) + if (receiptsRoot != m_currentBlock.receiptsRoot()) { InvalidReceiptsStateRoot ex; - ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot()); ex << errinfo_receipts(receipts); ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } - if (m_currentBlock.logBloom != logBloom()) + if (m_currentBlock.logBloom() != logBloom()) { InvalidLogBloom ex; - ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom()); ex << errinfo_receipts(receipts); BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. - u256 tdIncrease = m_currentBlock.difficulty; + u256 tdIncrease = m_currentBlock.difficulty(); // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) @@ -686,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) vector rewarded; h256Hash excluded; DEV_TIMED_ABOVE("allKin", 500) - excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; @@ -710,22 +708,22 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) + if (!_bc.isKnown(uncle.parentHash())) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + uncleParent = BlockInfo(_bc.block(uncle.parentHash())); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7) { UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } - else if (uncle.number == m_currentBlock.number) + else if (uncle.number() == m_currentBlock.number()) { UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } uncle.verifyParent(uncleParent); @@ -748,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash()) { m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot())); } - if (m_currentBlock.gasUsed != gasUsed()) + if (m_currentBlock.gasUsed() != gasUsed()) { // Rollback the trie. m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed()))); } return tdIncrease; @@ -772,7 +770,7 @@ void State::cleanup(bool _fullCommit) // Commit the new trie to disk. if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -786,7 +784,7 @@ void State::cleanup(bool _fullCommit) m_db.commit(); if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -806,7 +804,7 @@ void State::uncommitToMine() { m_cache.clear(); if (!m_transactions.size()) - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); else m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; @@ -878,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock.number != 0) + if (m_previousBlock.number() != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); - auto p = m_previousBlock.parentHash; +// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl; + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; @@ -926,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = hash256(transactionsMap); - m_currentBlock.receiptsRoot = hash256(receiptsMap); - m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); - // Apply rewards last of all. applyRewards(uncleBlockHeaders); @@ -941,12 +934,18 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // cnote << m_state; // cnote << *this; - m_currentBlock.gasUsed = gasUsed(); - m_currentBlock.stateRoot = m_state.root(); - m_currentBlock.parentHash = m_previousBlock.hash(); - m_currentBlock.extraData = _extraData; - if (m_currentBlock.extraData.size() > 32) - m_currentBlock.extraData.resize(32); + m_currentBlock.setLogBloom(logBloom()); + m_currentBlock.setGasUsed(gasUsed()); + m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root()); + + m_currentBlock.setParentHash(m_previousBlock.hash()); + m_currentBlock.setExtraData(_extraData); + if (m_currentBlock.extraData().size() > 32) + { + auto ed = m_currentBlock.extraData(); + ed.resize(32); + m_currentBlock.setExtraData(ed); + } m_committedToMine = true; } @@ -967,13 +966,13 @@ bool State::sealBlock(bytesConstRef _header) ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); - cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; + cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")"; // TODO: move into Sealer StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), "", // Can't give the nonce here. "", //TODO: chain head hash here ?? - m_currentBlock.parentHash.abridged() + m_currentBlock.parentHash().abridged() ); // Quickly reset the transactions. @@ -1270,7 +1269,7 @@ State State::fromPending(unsigned _i) const ret.m_cache.clear(); _i = min(_i, m_transactions.size()); if (!_i) - ret.m_state.setRoot(m_previousBlock.stateRoot); + ret.m_state.setRoot(m_previousBlock.stateRoot()); else ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) @@ -1287,10 +1286,10 @@ void State::applyRewards(vector const& _uncleBlockHeaders) u256 r = m_blockReward; for (auto const& i: _uncleBlockHeaders) { - addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8); + addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8); r += m_blockReward / 32; } - addBalance(m_currentBlock.coinbaseAddress, r); + addBalance(m_currentBlock.coinbaseAddress(), r); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) diff --git a/libethereum/State.h b/libethereum/State.h index 805215ee5..e2bda6f24 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } + u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); } /// Check if the address is in use. bool addressInUse(Address _address) const; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..a5c45af26 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -83,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry ): LogEntry(_le), blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), + blockNumber((BlockNumber)_bi.number()), transactionHash(_th), transactionIndex(_ti), logIndex(_li), @@ -205,7 +205,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } + h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2b2ada0ae..f95481c54 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress()); break; case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); + m_stack.push_back(_ext.currentBlock.timestamp()); break; case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); + m_stack.push_back(_ext.currentBlock.number()); break; case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); + m_stack.push_back(_ext.currentBlock.difficulty()); break; case Instruction::GASLIMIT: - m_stack.push_back(_ext.currentBlock.gasLimit); + m_stack.push_back(_ext.currentBlock.gasLimit()); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libtestutils/BlockChainLoader.cpp b/libtestutils/BlockChainLoader.cpp index e6c47e2fe..7e08243af 100644 --- a/libtestutils/BlockChainLoader.cpp +++ b/libtestutils/BlockChainLoader.cpp @@ -36,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) // load genesisBlock m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); - assert(m_state.rootHash() == m_bc->info().stateRoot); + assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks for (auto const& block: _json["blocks"]) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 15d39bded..fae12708c 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -88,18 +88,18 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) if (_bi) { res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["parentHash"] = toJS(_bi.parentHash()); + res["sha3Uncles"] = toJS(_bi.sha3Uncles()); + res["miner"] = toJS(_bi.coinbaseAddress()); + res["stateRoot"] = toJS(_bi.stateRoot()); + res["transactionsRoot"] = toJS(_bi.transactionsRoot()); res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); + res["number"] = toJS(_bi.number()); res["gasUsed"] = toJS(_bi.gasUsed); res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["logsBloom"] = toJS(_bi.logBloom); + res["timestamp"] = toJS(_bi.timestamp()); + res["extraData"] = toJS(_bi.extraData()); + res["logsBloom"] = toJS(_bi.logBloom()); res["target"] = toJS(_bi.boundary()); // TODO: move into ProofOfWork. @@ -140,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number())); } return res; } @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()); + res["stateRoot"] = toJS(_t.stateRoot()()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b43c4db51..bae980a7e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -151,12 +151,12 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); m_environment.currentBlock.number = toInt(_o["currentNumber"]); m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 9ee93779e..7dbc5c91e 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(blocks) u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString()); h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString())); h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); - ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom); - ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress); + ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); + ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), - _blockInfo.extraData.begin(), - _blockInfo.extraData.end() + _blockInfo.extraData().begin(), + _blockInfo.extraData().end() ); ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); @@ -132,11 +132,11 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); - ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp); - ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles); + ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); + ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; BlockInfo blockInfo = _client.blockInfo(blockHash); diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 20f60618f..cf44dfd9f 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -66,7 +66,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,9 +76,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot = trueState.rootHash(); + biGenesisBlock.stateRoot() = trueState.rootHash(); else - TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -125,7 +125,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TransientDirectory td_stateDB, td_bc; BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -225,7 +225,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); updatePoW(current_BlockHeader); } @@ -302,7 +302,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (o.count("expect") > 0) { stateOptionsMap expectStateMap; - State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); @@ -313,7 +313,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section - State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); }//_fillin @@ -374,19 +374,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); @@ -551,7 +551,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp = (u256)time(0); + uncleBlockFromFields.timestamp() = (u256)time(0); cnote << "uncle block n = " << toString(uncleBlockFromFields.number); if (_vBiBlocks.size() > 2) { @@ -568,15 +568,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash; - uncleBlockFromFields.stateRoot = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot; + uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); + uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); if (overwrite == "timestamp") { - uncleBlockFromFields.timestamp = toInt(uncleHeaderObj["timestamp"]); + uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); } } @@ -660,19 +660,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { BlockInfo tmp = _header; if (ho.count("parentHash")) - tmp.parentHash = h256(ho["parentHash"].get_str()); + tmp.parentHash() = h256(ho["parentHash"].get_str()); if (ho.count("uncleHash")) - tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); if (ho.count("coinbase")) - tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); if (ho.count("stateRoot")) - tmp.stateRoot = h256(ho["stateRoot"].get_str()); + tmp.stateRoot() = h256(ho["stateRoot"].get_str()); if (ho.count("transactionsTrie")) - tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); if (ho.count("receiptTrie")) - tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); if (ho.count("bloom")) - tmp.logBloom = LogBloom(ho["bloom"].get_str()); + tmp.logBloom() = LogBloom(ho["bloom"].get_str()); if (ho.count("difficulty")) tmp.difficulty = toInt(ho["difficulty"]); if (ho.count("number")) @@ -682,9 +682,9 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) if (ho.count("gasUsed")) tmp.gasUsed = toInt(ho["gasUsed"]); if (ho.count("timestamp")) - tmp.timestamp = toInt(ho["timestamp"]); + tmp.timestamp() = toInt(ho["timestamp"]); if (ho.count("extraData")) - tmp.extraData = importByteArray(ho["extraData"].get_str()); + tmp.extraData() = importByteArray(ho["extraData"].get_str()); // find new valid nonce if (tmp != _header && tmp.difficulty) @@ -751,19 +751,19 @@ mArray writeTransactionsToJson(Transactions const& txs) mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) { - _o["parentHash"] = toString(_bi.parentHash); - _o["uncleHash"] = toString(_bi.sha3Uncles); - _o["coinbase"] = toString(_bi.coinbaseAddress); - _o["stateRoot"] = toString(_bi.stateRoot); - _o["transactionsTrie"] = toString(_bi.transactionsRoot); - _o["receiptTrie"] = toString(_bi.receiptsRoot); - _o["bloom"] = toString(_bi.logBloom); + _o["parentHash"] = toString(_bi.parentHash()); + _o["uncleHash"] = toString(_bi.sha3Uncles()); + _o["coinbase"] = toString(_bi.coinbaseAddress()); + _o["stateRoot"] = toString(_bi.stateRoot()); + _o["transactionsTrie"] = toString(_bi.transactionsRoot()); + _o["receiptTrie"] = toString(_bi.receiptsRoot()); + _o["bloom"] = toString(_bi.logBloom()); _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); - _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); + _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); _o["hash"] = toString(_bi.hash()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 02ff4517a..2d5a2faa6 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index fdfb180fb..28b2e43ab 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -83,10 +83,10 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st mObject FakeExtVM::exportEnv() { mObject ret; - ret["previousHash"] = toString(currentBlock.parentHash); + ret["previousHash"] = toString(currentBlock.parentHash()); ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); - ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp, HexPrefix::Add, 1); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); return ret; @@ -102,13 +102,13 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash = h256(_o["previousHash"].get_str()); + currentBlock.parentHash() = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } mObject FakeExtVM::exportState() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d44545145..4a6507cd6 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1188,7 +1188,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " return block.timestamp() == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/third/MainWin.cpp b/third/MainWin.cpp index f2a90cc0b..a3b05572f 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From 86d2a1cb7ad98e0f9e5d93dd108c6f0ba04361ba Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:34:11 +0200 Subject: [PATCH 066/113] Minor fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ec37302a2..357926d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -98,7 +98,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + bc().rescue(m_stateDB); m_gp->update(bc()); From f817397991a61ffc2556b8bb4bf85e0d02ff7b2a Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 11:43:23 +0200 Subject: [PATCH 067/113] fixed build --- evmjit/libevmjit-cpp/JitVM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 4e1fb66ea..d96da87c1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -42,10 +42,10 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); - m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); - m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); - m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); + m_data.difficulty = eth2jit(_ext.currentBlock.difficulty()); + m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit()); + m_data.number = static_cast(_ext.currentBlock.number()); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); From d1f401ce4136609f09b5c1f5c012a57fbba31846 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 16:45:23 +0200 Subject: [PATCH 068/113] mix working --- CMakeLists.txt | 28 +++++++------- alethzero/MainWin.cpp | 53 ++++++++++++++------------- alethzero/MiningView.cpp | 4 +- alethzero/MiningView.h | 4 +- exp/CMakeLists.txt | 4 +- libethereum/BlockChain.cpp | 1 - libtestutils/BlockChainLoader.cpp | 3 +- libtestutils/StateLoader.cpp | 2 +- libtestutils/StateLoader.h | 2 + libweb3jsonrpc/JsonHelper.cpp | 8 ++-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libwebthree/WebThree.cpp | 2 +- mix/ClientModel.cpp | 4 +- mix/MixClient.cpp | 36 +++++++++--------- mix/MixClient.h | 36 +++++++++++++++--- 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b410d875c..89d3c167a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,13 +403,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) -# add_subdirectory(libweb3jsonrpc) + add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) -# add_subdirectory(libjsengine) -# add_subdirectory(libjsconsole) -# add_subdirectory(ethconsole) + add_subdirectory(libjsengine) + add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -437,31 +437,31 @@ add_subdirectory(libethcore) if (GENERAL) add_subdirectory(libevm) add_subdirectory(libethereum) -# add_subdirectory(libwebthree) + add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) -# add_subdirectory(ethminer) + add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) -# add_subdirectory(ethkey) + add_subdirectory(ethkey) endif () if (TESTS) -# add_subdirectory(libtestutils) -# add_subdirectory(test) + add_subdirectory(libtestutils) + add_subdirectory(test) if (JSONRPC) -# add_subdirectory(ethrpctest) + add_subdirectory(ethrpctest) endif () endif () if (TOOLS) -# add_subdirectory(rlp) -# add_subdirectory(abi) -# add_subdirectory(ethvm) -# add_subdirectory(eth) + add_subdirectory(rlp) + add_subdirectory(abi) + add_subdirectory(ethvm) + add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ad8f5528c..181772ddb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,9 +189,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; - auto block = CanonBlockChain::createGenesisBlock(); - cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl; @@ -208,13 +208,14 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); @@ -1124,7 +1125,7 @@ void Main::refreshMining() QString t; if (gp.first != EthashAux::NotGenerating) t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second); - MiningProgress p = ethereum()->miningProgress(); + WorkingProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining")); if (ethereum()->isMining() && p.hashes > 0) { @@ -1629,7 +1630,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1699,7 +1700,7 @@ void Main::on_blocks_currentItemChanged() auto details = ethereum()->blockChain().details(h); auto blockData = ethereum()->blockChain().block(h); auto block = RLP(blockData); - BlockInfo info(blockData); + Ethash::BlockHeader info(blockData); stringstream s; @@ -1709,21 +1710,21 @@ void Main::on_blocks_currentItemChanged() time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; - s << "

#" << info.number; + s << "

#" << info.number(); s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
"; s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; - s << "
Mix hash: " << info.mixHash << "" << "
"; - s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; - s << "
Difficulty: " << info.difficulty << "" << "
"; - if (info.number) + s << "
Mix hash: " << info.mixHash() << "" << "
"; + s << "
Nonce: " << info.nonce() << "" << "
"; + s << "
Hash w/o nonce: " << info.hashWithout() << "" << "
"; + s << "
Difficulty: " << info.difficulty() << "" << "
"; + if (info.number()) { - auto e = EthashAux::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce()); + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash() << "" << "
"; } else @@ -1740,19 +1741,19 @@ void Main::on_blocks_currentItemChanged() s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { - BlockInfo uncle = BlockInfo::fromHeader(u.data()); + Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; s << line << "Parent: " << uncle.parentHash() << "" << ""; - s << line << "Number: " << uncle.number << "" << ""; + s << line << "Number: " << uncle.number() << "" << ""; s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; - s << line << "Mix hash: " << uncle.mixHash << "" << ""; - s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Mix hash: " << uncle.mixHash() << "" << ""; + s << line << "Nonce: " << uncle.nonce() << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; - s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = EthashAux::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; + s << line << "Difficulty: " << uncle.difficulty() << "" << ""; + auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce()); + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash()) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; @@ -1764,7 +1765,7 @@ void Main::on_blocks_currentItemChanged() unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } s << "
Post: " << info.stateRoot() << "" << "
"; @@ -1807,7 +1808,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index e020408ea..fb9de0346 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MiningProgress; +using dev::eth::WorkingProgress; // functions using dev::toString; @@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MiningProgress const& _p) +void MiningView::appendStats(list const& _i, WorkingProgress const& _p) { (void)_p; if (_i.empty()) diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 65b9f2ec9..ae81a7cc4 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); + void appendStats(std::list const& _l, dev::eth::WorkingProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MiningProgress m_progress; + dev::eth::WorkingProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 5f876a69b..a9bc09db7 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,10 +18,10 @@ if (READLINE_FOUND) endif() if (JSONRPC) -# target_link_libraries(${EXECUTABLE} web3jsonrpc) + target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -#target_link_libraries(${EXECUTABLE} webthree) +target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b696c77bd..03ab1b46a 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -137,7 +137,6 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map #include "BlockChainLoader.h" #include "StateLoader.h" #include "Common.h" @@ -35,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) m_state = sl.state(); // load genesisBlock - m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); + m_bc.reset(new FullBlockChain(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill)); assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks diff --git a/libtestutils/StateLoader.cpp b/libtestutils/StateLoader.cpp index 235f1c573..cd5c37e96 100644 --- a/libtestutils/StateLoader.cpp +++ b/libtestutils/StateLoader.cpp @@ -27,7 +27,7 @@ using namespace dev::eth; using namespace dev::test; StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): - m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty) + m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty) { for (string const& name: _json.getMemberNames()) { diff --git a/libtestutils/StateLoader.h b/libtestutils/StateLoader.h index 47eb26900..c66f53148 100644 --- a/libtestutils/StateLoader.h +++ b/libtestutils/StateLoader.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace dev { @@ -38,6 +39,7 @@ class StateLoader public: StateLoader(Json::Value const& _json, std::string const& _dbPath); eth::State const& state() const { return m_state; } + eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; } private: eth::State m_state; diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index fae12708c..54fde52e8 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -93,10 +93,10 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["miner"] = toJS(_bi.coinbaseAddress()); res["stateRoot"] = toJS(_bi.stateRoot()); res["transactionsRoot"] = toJS(_bi.transactionsRoot()); - res["difficulty"] = toJS(_bi.difficulty); + res["difficulty"] = toJS(_bi.difficulty()); res["number"] = toJS(_bi.number()); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); + res["gasUsed"] = toJS(_bi.gasUsed()); + res["gasLimit"] = toJS(_bi.gasLimit()); res["timestamp"] = toJS(_bi.timestamp()); res["extraData"] = toJS(_bi.extraData()); res["logsBloom"] = toJS(_bi.logBloom()); @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()()); + res["stateRoot"] = toJS(_t.stateRoot()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 3aff9cf23..bf49d3322 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str return true; } -dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +dev::eth::BlockChain const& WebThreeStubServer::bc() const { return m_web3.ethereum()->blockChain(); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4d545c90e..2860f852b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -34,7 +34,7 @@ namespace eth { class KeyManager; class TrivialGasPricer; -class CanonBlockChain; +class BlockChain; class BlockQueue; } @@ -89,7 +89,7 @@ private: private: h256 blockHash(std::string const& _blockNumberOrHash) const; - dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockChain const& bc() const; dev::eth::BlockQueue const& bq() const; dev::WebThreeDirect& m_web3; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 3c1dea40f..7889b5935 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect( Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) { - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); + m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr(), _dbPath, _we, 0)); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 90ff19feb..5c5f2f4cd 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); stringstream strGas; - strGas << blockInfo.gasUsed; + strGas << blockInfo.gasUsed(); stringstream strNumber; - strNumber << blockInfo.number; + strNumber << blockInfo.number(); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ea4686601..eef6ad6ec 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -24,12 +24,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include "Exceptions.h" using namespace std; @@ -45,22 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho namespace { +} -struct MixPow //dummy POW +MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot): + FullBlockChain(createGenesisBlock(_stateRoot), std::unordered_map(), _path, WithExisting::Kill) { - typedef int Solution; - static bool verify(BlockInfo const&) { return true; } -}; - } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(15) + block.appendList(13) << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); + << std::string(); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -78,7 +77,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,12 +89,13 @@ void MixClient::resetState(std::unordered_map const& _accounts SecureTrieDB accountState(&m_stateDB); accountState.init(); - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + dev::eth::commit(_accounts, accountState); h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); + State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + s.sync(bc()); + m_state = s; m_startState = m_state; WriteGuard lx(x_executions); m_executions.clear(); @@ -275,11 +274,14 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + + NoProof::BlockHeader h(m_state.info()); + RLPStream header; + h.streamRLP(header); + m_state.sealBlock(header.out()); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; } ExecutionResult MixClient::lastExecution() const @@ -383,9 +385,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MiningProgress MixClient::miningProgress() const +eth::WorkingProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::WorkingProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..279692de5 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,13 +33,40 @@ namespace dev { + namespace mix { -class MixBlockChain: public dev::eth::BlockChain +class NoProof +{ + class BlockHeaderRaw: public dev::eth::BlockInfo + { + public: + static const unsigned SealFields = 0; + + protected: + BlockHeaderRaw() = default; + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; } + void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; } + void streamRLPFields(RLPStream& _s) const { (void) _s; } + }; + +public: + + static std::string name() { return "NoProof"; } + static unsigned revision() { return 0; } + using BlockHeader = dev::eth::BlockHeaderPolished; + +private: + static AddressHash s_authorities; +}; + +class MixBlockChain: public dev::eth::FullBlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {} + MixBlockChain(std::string const& _path, h256 _stateRoot); static bytes createGenesisBlock(h256 _stateRoot); }; @@ -67,9 +95,7 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MiningProgress miningProgress() const override; - eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } - bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } + eth::WorkingProgress miningProgress() const override; virtual void flushTransactions() override {} /// @returns the last mined block information From 32e90ddcd16358c45beaeafeeb6e8edfdb786ca2 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 18:11:08 +0200 Subject: [PATCH 069/113] started tests refactoring --- libethcore/Common.h | 3 ++- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 9 +++++---- libethereum/BlockQueue.cpp | 2 +- libethereum/Client.cpp | 3 +-- mix/MixClient.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libethcore/dagger.cpp | 4 ++-- test/libethereum/ClientBase.cpp | 14 +++++++------- test/libethereum/genesis.cpp | 6 +++--- test/libethereum/stateOriginal.cpp | 5 +++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 5c0a0cc79..116e1d5ed 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -130,9 +130,10 @@ struct ImportRequirements TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, None = 0 }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 03ab1b46a..8a654fa51 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 3ff85c8a6..811da8609 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -118,12 +118,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -391,7 +391,8 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash())); + if ((_ir & ImportRequirements::Parent) != 0) + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c9ee4c1cf..d0ca34b1c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); } catch (...) { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 357926d03..d43f240b7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -84,10 +84,9 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database // until after the construction. m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); - m_preMine = State(m_stateDB); - m_postMine = State(m_stateDB); // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. m_preMine = bc().genesisState(m_stateDB); + m_postMine = m_preMine; m_bq.setChain(bc()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index eef6ad6ec..67f2a2507 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -279,7 +279,7 @@ void MixClient::mine() RLPStream header; h.streamRLP(header); m_state.sealBlock(header.out()); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bae980a7e..30f323369 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,7 +63,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 061b5ae79..8d4cba933 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); - BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); + BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); BOOST_REQUIRE_EQUAL(nonce, header.nonce); unsigned cacheSize(o["cache_size"].get_int()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 7dbc5c91e..a426ff53f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -119,21 +119,21 @@ BOOST_AUTO_TEST_CASE(blocks) h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); - ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); + ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty()); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), _blockInfo.extraData().begin(), _blockInfo.extraData().end() ); - ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); - ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); + ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit()); + ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed()); ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash()); - ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); - ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); - ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); + ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash()); + ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce()); + ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number()); ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 2d5a2faa6..39997572f 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,9 +60,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e3f8ac29f..163c89e50 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ BOOST_AUTO_TEST_CASE(Complex) Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; + OverlayDB stateDB = State::openDB(h256()); + CanonBlockChain bc; cout << bc; State s = bc.genesisState(stateDB); From 697e42f9e4ff2cd4b45151547cd082e5ea7729b3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 20:53:58 +0200 Subject: [PATCH 070/113] eth working --- eth/main.cpp | 2 +- ethminer/MinerAux.h | 26 ++++++++++++-------------- libethcore/BlockInfo.h | 1 + libethereum/Client.h | 6 +++++- test/TestHelper.cpp | 17 ++++++++++++----- test/libethcore/dagger.cpp | 6 +++--- test/libethereum/ClientBase.cpp | 4 ++-- test/libethereum/gaspricer.cpp | 3 ++- test/libevm/vm.cpp | 10 +++++----- 9 files changed, 43 insertions(+), 32 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 7ce4d49c2..0b83c97b4 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1310,7 +1310,7 @@ int main(int argc, char** argv) { try { - CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); } catch (...) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 0d227b1ef..01083012f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -397,17 +397,16 @@ public: private: void doInitDAG(unsigned _n) { - BlockInfo bi; - bi.number() = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; - Ethash::prep(bi); + h256 seedHash = EthashAux::seedHash(_n); + cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl; + EthashAux::full(seedHash, true); exit(0); } void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) { - BlockInfo genesis; - genesis.difficulty = 1 << 18; + Ethash::BlockHeader genesis; + genesis.setDifficulty(1 << 18); cdebug << genesis.boundary(); GenericFarm f; @@ -417,17 +416,16 @@ private: cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; - Ethash::prep(genesis); + genesis.prep(); - genesis.difficulty = u256(1) << 63; - genesis.noteDirty(); + genesis.setDifficulty(u256(1) << 63); f.setWork(genesis); if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); - map results; + map results; uint64_t mean = 0; uint64_t innerMean = 0; for (unsigned i = 0; i <= _trials; ++i) @@ -488,9 +486,9 @@ private: Farm rpc(client); GenericFarm f; if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 67a5397f4..c310b3dd9 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -128,6 +128,7 @@ public: void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } Address const& coinbaseAddress() const { return m_coinbaseAddress; } h256 const& stateRoot() const { return m_stateRoot; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 73609bd71..4523d324b 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -77,7 +77,7 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); * @brief Main API hub for interfacing with Ethereum. * Not to be used directly - subclass. */ -class Client: public ClientBase, Worker +class Client: public ClientBase, protected Worker { public: /// New-style Constructor. @@ -342,6 +342,8 @@ public: init(_host, _dbPath, _forceAction, _networkId); } + virtual ~SpecialisedClient() { stopWorking(); } + /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } @@ -365,6 +367,8 @@ public: u256 _networkId = 0 ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + virtual ~EthashClient() { stopWorking(); } + /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. virtual std::tuple getEthashWork() override; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 30f323369..c29788b9f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -63,11 +64,17 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + Ethash::BlockHeader header(s.info); + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { - return completed = s.completeMine(sol); + header.m_mixHash = sol.mixHash; + header.m_nonce = sol.nonce; + RLPStream ret; + header.streamRLP(ret); + s.sealBlock(ret); + return true; }); f.setWork(s.info()); f.startCPU(); @@ -77,9 +84,9 @@ void mine(State& s, BlockChain const& _bc) void mine(BlockInfo& _bi) { - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { _bi.proof = sol; return completed = true; diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 8d4cba933..c3cd75b0d 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(basic_test) h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); - BOOST_REQUIRE_EQUAL(nonce, header.nonce); + BOOST_REQUIRE_EQUAL(nonce, header.nonce()); unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - EthashProofOfWork::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header.seedHash(), header.hashWithout(), header.nonce()); BOOST_REQUIRE_EQUAL(r.value, result); - BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); + BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash()); } } diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index a426ff53f..f9d83e9c6 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber); // blockInfo - auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void + auto compareBlockInfos = [](Json::Value const& _b, Ethash::BlockHeader _blockInfo) -> void { LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString())); Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString())); @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - BlockInfo blockInfo = _client.blockInfo(blockHash); + Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index ce49a4a20..050ab2d25 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer) std::shared_ptr gp(new TrivialGasPricer); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); - gp->update(BlockChain(bytes(), TransientDirectory().path(), WithExisting::Kill)); + gp->update(FullBlockChain(bytes(), StateDefinition(), TransientDirectory().path(), WithExisting::Kill)); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 28b2e43ab..badabd70c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number()), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -84,11 +84,11 @@ mObject FakeExtVM::exportEnv() { mObject ret; ret["previousHash"] = toString(currentBlock.parentHash()); - ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); + ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1); ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); - ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); - ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); + ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1); + ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1); return ret; } @@ -107,7 +107,7 @@ void FakeExtVM::importEnv(mObject& _o) lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } From 361c073bdc5ea2d38705a106d0edbc0888021826 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jul 2015 18:59:19 -0700 Subject: [PATCH 071/113] Modularise nonce, mix hash and seed hash. --- alethzero/MainWin.cpp | 4 +-- ethminer/MinerAux.h | 10 +++---- exp/main.cpp | 2 +- libethcore/BlockInfo.cpp | 45 +++++++++++++----------------- libethcore/BlockInfo.h | 26 +++++++++--------- libethcore/Common.cpp | 5 ++-- libethcore/Common.h | 1 + libethcore/Ethash.cpp | 52 ++++++++++++++++++++++++++++------- libethcore/Ethash.h | 16 +++++++++-- libethcore/EthashAux.cpp | 7 ++++- libethcore/EthashAux.h | 2 +- libethcore/ProofOfWork.h | 1 - libethereum/BlockChain.cpp | 8 +++--- libethereum/BlockQueue.cpp | 12 ++++---- libethereum/State.cpp | 8 +++--- libethereum/State.h | 4 +-- libweb3jsonrpc/JsonHelper.cpp | 7 +++-- mix/MixClient.cpp | 1 - test/TestHelper.cpp | 2 +- 19 files changed, 128 insertions(+), 85 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e48b58283..4655240e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1718,7 +1718,7 @@ void Main::on_blocks_currentItemChanged() s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { @@ -1749,7 +1749,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ff28132b1..5c6112743 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -254,17 +254,17 @@ public: bi.difficulty = u256(m); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bi.proof.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; exit(0); } catch (...) @@ -382,7 +382,7 @@ private: { BlockInfo bi; bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/exp/main.cpp b/exp/main.cpp index 88608f8cf..9884bd0e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -197,7 +197,7 @@ int main() bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, bi); + bi.proof = sol; return completed = true; }); f.setWork(bi); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index fec5b4678..c7acd9091 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -26,7 +26,6 @@ #include #include #include "EthashAux.h" -#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -57,22 +56,21 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - mixHash = h256(); - nonce = Nonce(); - m_hash = m_seedHash = h256(); + proof = ProofOfWork::Solution(); + m_proofCache = ProofOfWork::HeaderCache(); + m_hash = h256(); } -h256 const& BlockInfo::seedHash() const +ProofOfWork::HeaderCache const& BlockInfo::proofCache() const { - if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); - return m_seedHash; + ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); + return m_proofCache; } h256 const& BlockInfo::hash() const { if (!m_hash) - m_hash = headerHash(WithNonce); + m_hash = headerHash(WithProof); return m_hash; } @@ -90,20 +88,20 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const return ret; } -h256 BlockInfo::headerHash(IncludeNonce _n) const +h256 BlockInfo::headerHash(IncludeProof _n) const { RLPStream s; streamRLP(s, _n); return sha3(s.out()); } -void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const +void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const { - _s.appendList(_n == WithNonce ? 15 : 13) + _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithNonce) - _s << mixHash << nonce; + if (_n == WithProof) + proof.streamRLP(_s); } h256 BlockInfo::headerHash(bytesConstRef _block) @@ -116,12 +114,12 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); - m_seedHash = h256(); + m_proofCache = ProofOfWork::HeaderCache(); int field = 0; try { - if (_header.itemCount() != 15) + if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); @@ -136,8 +134,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - mixHash = _header[field = 13].toHash(RLP::VeryStrict); - nonce = _header[field = 14].toHash(RLP::VeryStrict); + proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -152,22 +149,18 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ProofOfWork::composeException(ex, *this); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); - ex << errinfo_seedHash(seedHash()); ex << errinfo_target(boundary()); - ex << errinfo_mixHash(mixHash); - Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce); - ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); BOOST_THROW_EXCEPTION(ex); } else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); + ProofOfWork::composeExceptionPre(ex, *this); BOOST_THROW_EXCEPTION(ex); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 79c12ebb4..b77c47c6b 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -24,16 +24,17 @@ #include #include #include "Common.h" +#include "ProofOfWork.h" namespace dev { namespace eth { -enum IncludeNonce +enum IncludeProof { - WithoutNonce = 0, - WithNonce = 1 + WithoutProof = 0, + WithProof = 1 }; enum Strictness @@ -82,8 +83,7 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - h256 mixHash; - Nonce nonce; + typename ProofOfWork::Solution proof; BlockInfo(); explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} @@ -112,14 +112,13 @@ public: gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && extraData == _cmp.extraData && - mixHash == _cmp.mixHash && - nonce == _cmp.nonce; + proof == _cmp.proof; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } void clear(); - void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); } + void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); @@ -130,16 +129,17 @@ public: u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - h256 const& seedHash() const; + ProofOfWork::HeaderCache const& proofCache() const; h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeNonce _n) const; - void streamRLP(RLPStream& _s, IncludeNonce _n) const; + h256 headerHash(IncludeProof _n) const; + void streamRLP(RLPStream& _s, IncludeProof _n) const; private: - mutable h256 m_seedHash; + + mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; @@ -148,7 +148,7 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; + _bi.gasUsed << " " << _bi.timestamp; return _out; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 618703e22..41cd1bba8 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -26,6 +26,7 @@ #include #include "Exceptions.h" #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -112,9 +113,9 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset; string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; - string const c_space = c_border + string(76, ' ') + c_border; + string const c_space = c_border + string(76, ' ') + c_border + EthReset; stringstream ss; ss << c_line << endl; ss << c_space << endl; diff --git a/libethcore/Common.h b/libethcore/Common.h index 296f0d01d..1e0cdc3b1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -189,6 +189,7 @@ struct TransactionSkeleton Address to; u256 value; bytes data; + u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; u256 nonce = UndefinedU256; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9be76926d..6a4a1445f 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -46,6 +46,7 @@ #endif #include "BlockInfo.h" #include "EthashAux.h" +#include "Exceptions.h" using namespace std; using namespace std::chrono; @@ -56,6 +57,26 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); +void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +{ + if (!io_out) + io_out = EthashAux::seedHash((unsigned)_h.number); +} + +void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); + _ex << errinfo_mixHash(_bi.proof.mixHash); + _ex << errinfo_seedHash(_bi.proofCache()); + Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); + _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +} + +void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); +} + std::string Ethash::name() { return "Ethash"; @@ -66,12 +87,23 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) +{ + mixHash = _header[_field].toHash(RLP::VeryStrict); + nonce = _header[++_field].toHash(RLP::VeryStrict); +} + +void Ethash::Solution::streamRLP(RLPStream& io_rlp) const +{ + io_rlp << mixHash << nonce; +} + Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutNonce); - ret.seedHash = _bi.seedHash(); + ret.headerHash = _bi.headerHash(WithoutProof); + ret.seedHash = _bi.proofCache(); return ret; } @@ -84,7 +116,7 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { - EthashAux::full(_header.seedHash(), true, _f); + EthashAux::full(_header.proofCache(), true, _f); } bool Ethash::preVerify(BlockInfo const& _header) @@ -95,9 +127,9 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), + (uint64_t)(u64)_header.proof.nonce, + (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); return ret; @@ -115,7 +147,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -125,9 +157,9 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; + cwarn << "headerHash:" << _header.headerHash(WithoutProof); + cwarn << "nonce:" << _header.proof.nonce; + cwarn << "mixHash:" << _header.proof.mixHash; cwarn << "difficulty:" << _header.difficulty; cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 7ffd887d0..5640152f0 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -28,16 +28,20 @@ #include #include #include "Common.h" -#include "BlockInfo.h" #include "Miner.h" class ethash_cl_miner; namespace dev { + +class RLP; +class RLPStream; + namespace eth { +class BlockInfo; class EthashCLHook; class Ethash @@ -45,8 +49,17 @@ class Ethash public: using Miner = GenericMiner; + using HeaderCache = h256; + static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); + static void composeException(Exception& _ex, BlockInfo& _bi); + static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + struct Solution { + bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } + void populateFromRLP(RLP const& io_rlp, int& io_field); + void streamRLP(RLPStream& io_rlp) const; + static const unsigned Fields = 2; Nonce nonce; h256 mixHash; }; @@ -78,7 +91,6 @@ public: static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } class CPUMiner: public Miner, Worker { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index efb6066f7..db01f3c49 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,6 +200,11 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } +Ethash::Result EthashAux::eval(BlockInfo const& _header) +{ + return eval(_header, _header.proof.nonce); +} + #define DEV_IF_THROWS(X) try { X; } catch (...) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) @@ -252,7 +257,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { - return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); + return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index d5bd60d44..be07f579c 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -78,7 +78,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 764207aef..7b4298047 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -38,7 +38,6 @@ namespace eth * typename Solution * typename CPUMiner * typename GPUMiner - * void assignResult(BlockInfo&, Result) * and a few others. TODO */ using ProofOfWork = Ethash; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 768ed223f..aaafe7ce9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -575,8 +575,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash.abridged() @@ -666,8 +666,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f95a3880e..690fb60ee 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.hash; + bi.proof.mixHash = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.mixHash == work.hash) + if (it->verified.info.proof.mixHash == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.mixHash == work.hash) + if (i.verified.info.proof.mixHash == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..bf55a50ff 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -837,7 +837,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); + m_currentBlock.streamRLP(block, WithProof); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -902,7 +902,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithNonce); + ubi.streamRLP(unclesData, WithProof); ++unclesCount; uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) @@ -970,7 +970,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithNonce); + m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -978,7 +978,7 @@ void State::completeMine() cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.nonce.abridged(), + m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() ); diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..0555b6dcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -169,11 +169,11 @@ public: if (!m_committedToMine) return false; - PoW::assignResult(_result, m_currentBlock); + m_currentBlock.proof = _result; if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..f7c09ebc2 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -99,11 +99,12 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["gasLimit"] = toJS(_bi.gasLimit); res["timestamp"] = toJS(_bi.timestamp); res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); res["logsBloom"] = toJS(_bi.logBloom); - - res["seedHash"] = toJS(_bi.seedHash()); res["target"] = toJS(_bi.boundary()); + + // TODO: move into ProofOfWork. + res["nonce"] = toJS(_bi.proof.nonce); + res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 8373c7c51..ea4686601 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -49,7 +49,6 @@ namespace struct MixPow //dummy POW { typedef int Solution; - static void assignResult(int, BlockInfo const&) {} static bool verify(BlockInfo const&) { return true; } }; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f49ed1e09..b43c4db51 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(BlockInfo& _bi) bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, _bi); + _bi.proof = sol; return completed = true; }); f.setWork(_bi); From a00196914ac6c413e5ec6504d224df74cda203fa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 13:03:52 -0700 Subject: [PATCH 072/113] Basic Proof-of-Authority sealent. --- eth/main.cpp | 3 + ethminer/MinerAux.h | 28 +++++++-- libdevcrypto/Common.cpp | 5 ++ libdevcrypto/Common.h | 3 + libethcore/Common.cpp | 4 ++ libethcore/Common.h | 13 +++- libethcore/Ethash.cpp | 26 +++++++- libethcore/Ethash.h | 31 +++++++++ libethcore/EthashAux.cpp | 11 ++++ libethcore/EthashAux.h | 1 + libethcore/Farm.h | 1 - libethcore/Miner.h | 11 ---- libethcore/ProofOfWork.cpp | 25 ++++++++ libethcore/ProofOfWork.h | 76 ++++++++++++++++++++++- libethereum/BlockChain.cpp | 4 ++ libethereum/BlockQueue.cpp | 12 ++-- libethereum/Client.cpp | 15 +---- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 +- libethereum/State.h | 2 +- libweb3jsonrpc/JsonHelper.cpp | 2 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 10 ++- 22 files changed, 246 insertions(+), 43 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 5b38f2779..434860f59 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1700,7 +1700,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) { From d9372d67d10052242b7ce6595922ee8f435a3caf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH 073/113] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + 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 BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + 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 BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - 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); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) 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)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); - _ex << errinfo_mixHash(_bi.proof.mixHash); - _ex << errinfo_seedHash(_bi.proofCache()); - Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); - _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); -#else - (void)_ex; - (void)_bi; -#endif -} - -void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) -{ -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); -#else - (void)_ex; - (void)_bi; -#endif -} - -std::string Ethash::name() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) -{ - WorkPackage ret; - ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutProof); -#if ETH_USING_ETHASH - ret.seedHash = _bi.proofCache(); -#endif - return ret; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -void Ethash::prep(BlockInfo const& _header, std::function const& _f) -{ -#if ETH_USING_ETHASH - EthashAux::full(_header.proofCache(), true, _f); -#else - (void)_header; - (void)_f; -#endif + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (number >= ETHASH_EPOCH_LENGTH * 2048) return false; -#if ETH_USING_ETHASH - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ bool Ethash::verify(BlockInfo const& _header) } #endif -#if ETH_USING_ETHASH - auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + 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, unsigned, 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 + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - 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, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#else - using GPUMiner = CPUMiner; -#endif /// Default value of the local work size. Also known as workgroup size. static const unsigned defaultLocalWorkSize; /// Default value of the global work size as a multiplier of the local work size static const unsigned defaultGlobalWorkSizeMultiplier; /// Default value of the milliseconds per global work size (per batch) static const unsigned defaultMSPerBatch; - - struct Farm: public eth::GenericFarm - { - public: - strings sealers() const { return { "cpu", "opencl" }; } - void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } - - void sealBlock(BlockInfo const& _bi) - { - setWork(_bi); - if (m_opencl) - startGPU(); - else - startCPU(); - - setWork(_bi); - ensurePrecomputed((unsigned)_bi.number); - } - - void disable() { stop(); } - - private: - bool m_opencl = false; - }; }; } diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) - return true; - m_miners.clear(); - m_miners.reserve(MinerType::instances()); - for (unsigned i = 0; i < MinerType::instances(); ++i) - { - m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); - -bool BasicAuthority::verify(BlockInfo const& _header) -{ - return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; -} - -bool BasicAuthority::preVerify(BlockInfo const& _header) -{ - return SignatureStruct(_header.proof.sig).isValid(); -} - -BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) -{ - return WorkPackage{_header.headerHash(WithoutProof)}; -} - -void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) -{ - m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); -} - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -class BasicAuthority -{ -public: - struct HeaderCache {}; - static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} - static void composeException(Exception&, BlockInfo&) {} - static void composeExceptionPre(Exception&, BlockInfo&) {} - - struct Solution - { - bool operator==(Solution const& _v) const { return sig == _v.sig; } - void populateFromRLP(RLP const& io_rlp, int& io_field) - { - sig = io_rlp[io_field++].toHash(RLP::VeryStrict); - } - - void streamRLP(RLPStream& io_rlp) const - { - io_rlp << sig; - } - static const unsigned Fields = 1; - Signature sig; - }; - - struct Result - { - Signature sig; - }; - - struct WorkPackage - { - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } - - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - }; - - static const WorkPackage NullWorkPackage; - - static std::string name() { return "BasicAuthority"; } - static unsigned revision() { return 0; } - static void prep(BlockInfo const&, std::function const& = std::function()) {} - static void ensurePrecomputed(unsigned) {} - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - static const Address Authority; - - struct Farm - { - public: - strings sealers() const { return { "default" }; } - void setSealer(std::string const&) {} - void setSecret(Secret const& _s) { m_secret = _s; } - void sealBlock(BlockInfo const& _bi); - void disable() {} - void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } - - private: - Secret m_secret; - std::function m_onSolutionFound; - }; -}; - using ProofOfWork = BasicAuthority; } diff --git a/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + 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 Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + 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 Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady; From 3dbe96d51889bef81a11f7019964840f2a545796 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Jul 2015 16:32:04 -0700 Subject: [PATCH 074/113] Tests working for BasicAuthority and Ethash. --- CMakeLists.txt | 32 ++++++++++++++-------------- exp/CMakeLists.txt | 20 ++++++++++++------ exp/main.cpp | 40 ++++++++++++++++++++++++++--------- libdevcore/Common.h | 1 + libethcore/BasicAuthority.cpp | 18 +++++++++++++--- libethcore/BasicAuthority.h | 7 +++++- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 1 + libethcore/EthashAux.cpp | 23 -------------------- libethcore/EthashAux.h | 2 -- libethcore/Sealer.h | 12 +++++++++++ 12 files changed, 97 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d3c167a..1d35280e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,13 +403,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) - add_subdirectory(libweb3jsonrpc) +# add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) - add_subdirectory(libjsengine) - add_subdirectory(libjsconsole) - add_subdirectory(ethconsole) +# add_subdirectory(libjsengine) +# add_subdirectory(libjsconsole) +# add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -435,33 +435,33 @@ endif () add_subdirectory(libethcore) if (GENERAL) - add_subdirectory(libevm) - add_subdirectory(libethereum) - add_subdirectory(libwebthree) +# add_subdirectory(libevm) +# add_subdirectory(libethereum) +# add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) - add_subdirectory(ethminer) +# add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) - add_subdirectory(ethkey) +# add_subdirectory(ethkey) endif () if (TESTS) - add_subdirectory(libtestutils) - add_subdirectory(test) +# add_subdirectory(libtestutils) +# add_subdirectory(test) if (JSONRPC) - add_subdirectory(ethrpctest) +# add_subdirectory(ethrpctest) endif () endif () if (TOOLS) - add_subdirectory(rlp) - add_subdirectory(abi) - add_subdirectory(ethvm) - add_subdirectory(eth) +# add_subdirectory(rlp) +# add_subdirectory(abi) +# add_subdirectory(ethvm) +# add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 7a80023bf..30f4705f9 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,15 +18,21 @@ if (READLINE_FOUND) endif() if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) +# target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} p2p) +#target_link_libraries(${EXECUTABLE} webthree) +#target_link_libraries(${EXECUTABLE} ethereum) +#target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} ethash) - target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} ethash-cl) +# target_link_libraries(${EXECUTABLE} ethash) +# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) endif() +target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) + + + + + diff --git a/exp/main.cpp b/exp/main.cpp index 07eee6a11..fa8603459 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,6 +70,7 @@ namespace fs = boost::filesystem; #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -80,24 +81,43 @@ using namespace eth; int main() { BlockInfo bi; + bi.difficulty = c_genesisDifficulty; + bi.gasLimit = c_genesisGasLimit; + bi.number = 1; + bi.parentHash = sha3("parentHash"); + bytes sealedData; - SealEngineFace* se = BasicAuthority::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); - se->generateSeal(bi); { + KeyPair kp(sha3("test")); + SealEngineFace* se = BasicAuthority::createSealEngine(); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); + cdebug << se->sealers(); + bool done = false; + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.sig(); } - SealEngineFace* se = Ethash::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); - se->generateSeal(bi); - while (!done) - this_thread::sleep_for(chrono::milliseconds(50)); { + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + bool done = false; + se->setSealer("cpu"); + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.nonce(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 303512e57..612b7c685 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using byte = uint8_t; #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) namespace dev { diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index bbf4e3f2a..7006107e1 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); +AddressHash BasicAuthority::s_authorities; bool BasicAuthority::BlockHeaderRaw::verify() const { - return toAddress(recover(m_sig, hashWithout())) == Authority; + return s_authorities.count(toAddress(recover(m_sig, hashWithout()))); } bool BasicAuthority::BlockHeaderRaw::preVerify() const @@ -94,11 +94,23 @@ public: MiningProgress miningProgress() const { return MiningProgress(); } private: + virtual bool onOptionChanging(std::string const& _name, bytes const& _value) + { + RLP rlp(_value); + if (_name == "authorities") + BasicAuthority::s_authorities = rlp.toUnorderedSet
(); + else if (_name == "authority") + m_secret = rlp.toHash(); + else + return false; + return true; + } + Secret m_secret; std::function m_onSealGenerated; }; -SealEngineFace* createSealEngine() +SealEngineFace* BasicAuthority::createSealEngine() { return new BasicAuthoritySealEngine; } diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 616c18340..9127c1d53 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -30,6 +30,7 @@ #include "Sealer.h" class BasicAuthoritySeal; +class BasicAuthoritySealEngine; namespace dev { @@ -48,6 +49,8 @@ namespace eth */ class BasicAuthority { + friend class ::BasicAuthoritySealEngine; + public: // TODO: remove struct Result {}; @@ -70,6 +73,7 @@ public: Signature sig() const { return m_sig; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 1; @@ -84,7 +88,8 @@ public: }; using BlockHeader = BlockHeaderPolished; - static const Address Authority; +private: + static AddressHash s_authorities; }; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index cd55bc1f6..710279cb2 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -158,7 +158,7 @@ public: explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c3f19e723..d385163be 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -119,7 +119,7 @@ bool Ethash::BlockHeaderRaw::verify() const } #endif - auto result = EthashAux::eval(*this); + auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce); bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); @@ -281,6 +281,7 @@ public: { m_farm.onSolutionFound([=](Ethash::Solution const& sol) { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; EthashSeal s(sol.mixHash, sol.nonce); _f(&s); return true; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index eee0e3881..99baa8a05 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -94,6 +94,7 @@ public: h256 const& mixHash() const { return m_mixHash; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 2; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 42a3cf6fb..00537c21a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,18 +200,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } -Ethash::Result EthashAux::eval(BlockInfo const& _header) -{ -#if ETH_USING_ETHASH - return eval(_header, _header.proof.nonce); -#else - (void)_header; - return Ethash::Result(); -#endif -} - -#define DEV_IF_THROWS(X) try { X; } catch (...) - unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); @@ -260,17 +248,6 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) -{ -#if ETH_USING_ETHASH - return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); -#else - (void)_header; - (void)_nonce; - return Ethash::Result(); -#endif -} - Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 5ae24898d..132b9b436 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -79,8 +79,6 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header); - static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index f491240f3..28381444e 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include "Common.h" namespace dev @@ -43,6 +44,9 @@ public: class SealEngineFace { public: + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; @@ -52,6 +56,14 @@ public: // TODO: rename & generalise virtual bool isMining() const { return false; } virtual MiningProgress miningProgress() const { return MiningProgress(); } + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; }; } From d76b9b3d18e50d6d1cd076c81e425f4a7ee9d29b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jul 2015 23:24:10 +0200 Subject: [PATCH 075/113] Basic test working with same code for Ethash and BasicAuthority. --- CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 1 - ethminer/MinerAux.h | 17 +-- exp/CMakeLists.txt | 6 +- exp/main.cpp | 86 +++++++------ libdevcore/Guards.h | 29 +++++ libdevcore/RLP.h | 3 + libdevcore/TrieDB.h | 9 +- libethcore/BasicAuthority.cpp | 43 ++++--- libethcore/BasicAuthority.h | 16 +-- libethcore/BlockInfo.cpp | 34 +---- libethcore/BlockInfo.h | 64 ++++++--- libethcore/Common.cpp | 3 +- libethcore/Common.h | 14 +- libethcore/Ethash.cpp | 163 ++++++++++++----------- libethcore/Ethash.h | 52 ++------ libethcore/EthashAux.cpp | 17 ++- libethcore/EthashAux.h | 47 ++++++- libethcore/Farm.h | 6 +- libethcore/Miner.h | 4 +- libethcore/ProofOfWork.cpp | 27 ---- libethcore/ProofOfWork.h | 40 ------ libethcore/Sealer.h | 31 +++-- libethereum/BlockChain.cpp | 136 ++++++++++---------- libethereum/BlockChain.h | 113 ++++++++++++++-- libethereum/BlockChainSync.cpp | 11 +- libethereum/BlockQueue.cpp | 24 ++-- libethereum/BlockQueue.h | 8 +- libethereum/CanonBlockChain.cpp | 75 ++++++----- libethereum/CanonBlockChain.h | 45 ++++++- libethereum/Client.cpp | 200 ++++++++++++++++------------- libethereum/Client.h | 119 +++++++++++------ libethereum/ClientBase.cpp | 2 +- libethereum/ClientBase.h | 4 +- libethereum/Interface.h | 8 +- libethereum/State.cpp | 87 ++++++------- libethereum/State.h | 66 ++++------ libethereum/Utility.cpp | 4 +- libethereum/Utility.h | 3 +- libweb3jsonrpc/JsonHelper.cpp | 6 +- libweb3jsonrpc/JsonHelper.h | 14 ++ test/libethcore/dagger.cpp | 3 +- test/libethereum/stateOriginal.cpp | 3 +- 44 files changed, 933 insertions(+), 716 deletions(-) delete mode 100644 libethcore/ProofOfWork.cpp delete mode 100644 libethcore/ProofOfWork.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d35280e0..b410d875c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,8 +435,8 @@ endif () add_subdirectory(libethcore) if (GENERAL) -# add_subdirectory(libevm) -# add_subdirectory(libethereum) + add_subdirectory(libevm) + add_subdirectory(libethereum) # add_subdirectory(libwebthree) endif () diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4655240e3..2ee8928f5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -208,7 +208,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); diff --git a/eth/main.cpp b/eth/main.cpp index 434860f59..7ce4d49c2 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 051128669..61fde605d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #if ETH_ETHASHCL || !ETH_TRUE @@ -387,7 +386,6 @@ public: #endif } -#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -412,10 +410,10 @@ private: genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - GenericFarm f; - f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + GenericFarm f; + f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); - string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; @@ -488,20 +486,20 @@ private: jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; + GenericFarm f; if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) f.startGPU(); - ProofOfWork::WorkPackage current; + EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; while (true) try { bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) + EthashProofOfWork::Solution solution; + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { solution = sol; return completed = true; @@ -595,5 +593,4 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; -#endif }; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 30f4705f9..5f876a69b 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -22,12 +22,12 @@ if (JSONRPC) endif() #target_link_libraries(${EXECUTABLE} webthree) -#target_link_libraries(${EXECUTABLE} ethereum) -#target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) # target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash) -# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} OpenCL) endif() target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/exp/main.cpp b/exp/main.cpp index fa8603459..4a35068f1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -71,13 +70,16 @@ namespace fs = boost::filesystem; #include #include #include +#include +#include +#include +#include using namespace std; using namespace dev; using namespace eth; #endif -#if 1 - +#if 0 int main() { BlockInfo bi; @@ -124,9 +126,7 @@ int main() return 0; } - #elif 0 - int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); @@ -135,10 +135,7 @@ int main() cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); return 0; } - - #elif 0 - int main() { cdebug << "EXP"; @@ -162,9 +159,7 @@ int main() ret = orderedTrieRoot(data); cdebug << ret; } - #elif 0 - int main() { KeyManager keyman; @@ -186,7 +181,6 @@ int main() cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); } - #elif 0 int main() { @@ -246,15 +240,15 @@ int main() #elif 0 int main() { - GenericFarm f; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { BlockInfo bi = g; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { bi.proof = sol; return completed = true; @@ -289,23 +283,16 @@ int main() return 0; } -#elif 0 - -void mine(State& s, BlockChain const& _bc) +#elif 1 +void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) { s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - return completed = s.completeMine(sol); - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + _se->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); } -#elif 0 int main() { cnote << "Testing State..."; @@ -316,47 +303,62 @@ int main() Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; - cout << bc; + using Sealer = Ethash; + CanonBlockChain bc; + auto gbb = bc.headerData(bc.genesisHash()); + assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData)); + + SealEngineFace* se = Sealer::createSealEngine(); + KeyPair kp(sha3("test")); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); - cout << s; + OverlayDB stateDB = State::openDB(bc.genesisHash()); + cnote << bc; + + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); + cnote << s; // Sync up - this won't do much until we use the last state. s.sync(bc); - cout << s; + cnote << s; // Mine to get some ether! - mine(s, bc); + mine(s, bc, se); - bc.attemptImport(s.blockData(), stateDB); + bytes minedBlock = s.blockData(); + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + bc.import(minedBlock, stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; + cnote << "Miner now has" << s.balance(myMiner.address()); + s.resetCurrent(); + cnote << "Miner now has" << s.balance(myMiner.address()); // Inject a transaction to transfer funds from miner to me. Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); - cout << s; + cnote << s; // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - mine(s, bc); + mine(s, bc, se); bc.attemptImport(s.blockData(), stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; return 0; } diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 44d5969e4..135209d23 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex; using SharedMutex = boost::shared_mutex; using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; using RecursiveGuard = std::lock_guard; using ReadGuard = boost::shared_lock; using UpgradableGuard = boost::upgrade_lock; @@ -74,6 +76,33 @@ private: }; using SpinGuard = std::lock_guard; +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a94c8ba55..701f4b8e8 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -393,6 +393,9 @@ public: /// Read the byte stream. bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + /// Swap the contents of the output stream out for some other byte array. void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..05affa677 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -231,8 +231,11 @@ public: } } -protected: - DB* db() const { return m_db; } + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -383,6 +386,7 @@ public: using Super::isEmpty; using Super::root; + using Super::db; using Super::leftOvers; using Super::check; @@ -435,6 +439,7 @@ public: using Super::check; using Super::open; using Super::setRoot; + using Super::db; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7006107e1..22da67080 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -19,6 +19,7 @@ * @date 2014 */ +#include #include "Exceptions.h" #include "BasicAuthority.h" #include "BlockInfo.h" @@ -60,38 +61,38 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri } } +void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} +void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} -class BasicAuthoritySeal: public SealFace +StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const { -public: - BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + return { { "sig", toJS(m_sig) } }; +} - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - BasicAuthority::BlockHeader h(_bi); - h.m_sig = m_sig; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } -private: - Signature m_sig; -}; -class BasicAuthoritySealEngine: public SealEngineFace +class BasicAuthoritySealEngine: public SealEngineBase { public: void setSecret(Secret const& _s) { m_secret = _s; } void generateSeal(BlockInfo const& _bi) { - BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); - m_onSealGenerated(&s); + BasicAuthority::BlockHeader h(_bi); + h.m_sig = sign(m_secret, _bi.hashWithout()); + RLPStream ret; + h.streamRLP(ret); + m_onSealGenerated(ret.out()); } - void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isWorking() const { return false; } + WorkingProgress workingProgress() const { return WorkingProgress(); } private: virtual bool onOptionChanging(std::string const& _name, bytes const& _value) @@ -107,7 +108,7 @@ private: } Secret m_secret; - std::function m_onSealGenerated; + std::function m_onSealGenerated; }; SealEngineFace* BasicAuthority::createSealEngine() diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 9127c1d53..8db47938b 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -52,33 +52,31 @@ class BasicAuthority friend class ::BasicAuthoritySealEngine; public: - // TODO: remove - struct Result {}; - struct WorkPackage {}; - static const WorkPackage NullWorkPackage; - static std::string name() { return "BasicAuthority"; } static unsigned revision() { return 0; } static SealEngineFace* createSealEngine(); class BlockHeaderRaw: public BlockInfo { - friend class ::BasicAuthoritySeal; + friend class ::BasicAuthoritySealEngine; public: + static const unsigned SealFields = 1; + bool verify() const; bool preVerify() const; - WorkPackage package() const { return NullWorkPackage; } Signature sig() const { return m_sig; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 1; - void populateFromHeader(RLP const& _header, Strictness _s); + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); void streamRLPFields(RLPStream& _s) const { _s << m_sig; } void clear() { m_sig = Signature(); } void noteDirty() const {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb07162fb..64961bc40 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,10 +36,10 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt) { - RLP header = extractHeader(_block); - m_hash = sha3(header.data()); + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); populateFromHeader(header, _s); } @@ -58,7 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - m_hashWithout = h256(); + noteDirty(); } h256 const& BlockInfo::boundary() const @@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing) - { - if (gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); - - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); - - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); - - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); - } + if (_s != CheckNothing && gasUsed > gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) gasLimit = selectGasLimit(_parent); gasUsed = 0; difficulty = calculateDifficulty(_parent); + parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const @@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const void BlockInfo::verifyParent(BlockInfo const& _parent) const { - // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); - - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); - // Check timestamp is after previous timestamp. if (parentHash) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 710279cb2..b00fa73fb 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -42,10 +42,18 @@ enum Strictness { CheckEverything, QuickNonce, - IgnoreNonce, + IgnoreSeal, CheckNothing }; +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); + /** @brief Encapsulation of a block header. * Class to contain all of a block header's data. It is able to parse a block header and populate * from some given RLP block serialisation with the static fromHeader(), through the method @@ -69,7 +77,10 @@ enum Strictness */ struct BlockInfo { + friend class BlockChain; public: + static const unsigned BasicFields = 13; + // TODO: make them all private! h256 parentHash; h256 sha3Uncles; @@ -78,7 +89,7 @@ public: h256 transactionsRoot; h256 receiptsRoot; LogBloom logBloom; - u256 difficulty; + u256 difficulty; // TODO: pull out into BlockHeader u256 number; u256 gasLimit; u256 gasUsed; @@ -86,10 +97,12 @@ public: bytes extraData; BlockInfo(); - BlockInfo(bytesConstRef _block, Strictness _s); + explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); + explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -121,17 +134,14 @@ public: /// sha3 of the header only. h256 const& hashWithout() const; - h256 const& hash() const { return m_hash; } - -protected: - static RLP extractHeader(bytesConstRef _block); - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); - void streamRLPFields(RLPStream& _s) const; + h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } void clear(); void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } - static const unsigned BasicFields = 13; +protected: + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal); + void streamRLPFields(RLPStream& _s) const; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. @@ -152,35 +162,50 @@ template class BlockHeaderPolished: public BlockInfoSub { public: + static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields; + BlockHeaderPolished() {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} - explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } - explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); } + explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); } - static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } + // deprecated - just use constructor instead. + static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } + static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } - void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + // deprecated for public API - use constructor. + // TODO: make private. + void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData) + { + populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h); + } void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); BlockInfo::parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); + BlockInfoSub::populateFromParent(_parent); } + // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); + BlockInfoSub::verifyParent(_parent); } - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + // deprecated for public API - use constructor. + // TODO: make private. + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { BlockInfo::m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); + else + BlockInfo::m_hash = dev::sha3(_header.data()); if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); @@ -213,6 +238,13 @@ public: if (_i == WithProof) BlockInfoSub::streamRLPFields(_s); } + + bytes sealFieldsRLP() const + { + RLPStream s; + BlockInfoSub::streamRLPFields(s); + return s.out(); + } }; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 58e506b37..499854584 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -29,7 +29,6 @@ #include #include #include "Exceptions.h" -#include "ProofOfWork.h" #include "BlockInfo.h" using namespace std; using namespace dev; @@ -57,7 +56,7 @@ Network const c_network = Network::Frontier; Network const c_network = Network::Olympic; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 1a688fbd8..5c0a0cc79 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -124,10 +124,16 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, ///< Validate nonce + ValidSeal = 1, ///< Validate seal DontHave = 2, ///< Avoid old blocks - CheckUncles = 4, ///< Check uncle nonces - Default = ValidNonce | DontHave | CheckUncles + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures + Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + None = 0 }; }; @@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(& /** * @brief Describes the progress of a mining operation. */ -struct MiningProgress +struct WorkingProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index d385163be..128822b80 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "Exceptions.h" #include "Farm.h" #include "Miner.h" +#include "Params.h" using namespace std; using namespace std::chrono; @@ -57,8 +59,6 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); - h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) @@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); ex << errinfo_mixHash(m_mixHash); ex << errinfo_seedHash(seedHash()); - Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); ex << errinfo_difficulty(difficulty); @@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } + + if (_s != CheckNothing) + { + if (difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + + if (gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + + if (number && extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + } +} + +void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + + if (gasLimit < c_minGasLimit || + gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || + gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); +} + +void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; } bool Ethash::BlockHeaderRaw::preVerify() const @@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const return slow; } -Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const -{ - WorkPackage ret; - ret.boundary = boundary(); - ret.headerHash = hashWithout(); - ret.seedHash = seedHash(); - return ret; -} - void Ethash::BlockHeaderRaw::prep(std::function const& _f) const { EthashAux::full(seedHash(), true, _f); } +StringHashMap Ethash::BlockHeaderRaw::jsInfo() const +{ + return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; +} @@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function const& _f) const -class EthashCPUMiner: public GenericMiner, Worker +class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -190,7 +214,7 @@ private: }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker +class EthashGPUMiner: public GenericMiner, Worker { friend class dev::eth::EthashCLHook; @@ -234,66 +258,84 @@ private: }; #endif -class EthashSeal: public SealFace +struct EthashSealEngine: public SealEngineBase { -public: - EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} - - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - Ethash::BlockHeader h(_bi); - h.m_mixHash = m_mixHash; - h.m_nonce = m_nonce; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } - -private: - h256 m_mixHash; - h64 m_nonce; -}; + friend class Ethash; -struct EthashSealEngine: public SealEngineFace -{ public: EthashSealEngine() { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; #if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; #endif m_farm.setSealers(sealers); } - strings sealers() const override { return { "cpu", "opencl" }; } + strings sealers() const override + { + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; + } void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void disable() override { m_farm.stop(); } + void cancelGeneration() override { m_farm.stop(); } void generateSeal(BlockInfo const& _bi) override { - m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); m_farm.start(m_sealer); - m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + m_farm.setWork(m_sealing); // TODO: take out one before or one after... Ethash::ensurePrecomputed((unsigned)_bi.number); } - void onSealGenerated(std::function const& _f) override + void onSealGenerated(std::function const& _f) override { - m_farm.onSolutionFound([=](Ethash::Solution const& sol) + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) { cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - EthashSeal s(sol.mixHash, sol.nonce); - _f(&s); + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); return true; }); } private: bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; }; +void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + // Go via the farm since the handler function object is stored as a local within the Farm's lambda. + // Has the side effect of stopping local workers, which is good, as long as it only does it for + // valid submissions. + static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); +} + +bool Ethash::isWorking(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.isMining(); + return false; +} + +WorkingProgress Ethash::workingProgress(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.miningProgress(); + return WorkingProgress(); +} + SealEngineFace* Ethash::createSealEngine() { return new EthashSealEngine; @@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE -using UniqueGuard = std::unique_lock; - -template -class Notified -{ -public: - Notified() {} - Notified(N const& _v): m_value(_v) {} - Notified(Notified const&) = delete; - Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - - operator N() const { UniqueGuard l(m_mutex); return m_value; } - - void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } - -private: - mutable Mutex m_mutex; - mutable std::condition_variable m_cv; - N m_value; -}; - class EthashCLHook: public ethash_cl_miner::search_hook { public: diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99baa8a05..576621bd4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -53,59 +53,42 @@ public: static unsigned revision(); static SealEngineFace* createSealEngine(); - // TODO: remove or virtualize - struct Solution - { - h64 nonce; - h256 mixHash; - }; - // TODO: make private - struct Result - { - h256 value; - h256 mixHash; - }; - // TODO: virtualise - struct WorkPackage - { - WorkPackage() = default; - - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } + using Nonce = h64; - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; - }; - static const WorkPackage NullWorkPackage; + static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce); + static bool isWorking(SealEngineFace* _engine); + static WorkingProgress workingProgress(SealEngineFace* _engine); class BlockHeaderRaw: public BlockInfo { - friend class EthashSeal; + friend class EthashSealEngine; public: + static const unsigned SealFields = 2; + bool verify() const; bool preVerify() const; void prep(std::function const& _f = std::function()) const; - WorkPackage package() const; h256 const& seedHash() const; - h64 const& nonce() const { return m_nonce; } + Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 2; - void populateFromHeader(RLP const& _header, Strictness _s); - void clear() { m_mixHash = h256(); m_nonce = h64(); } + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); + void clear() { m_mixHash = h256(); m_nonce = Nonce(); } void noteDirty() const { m_seedHash = h256(); } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - h64 m_nonce; + Nonce m_nonce; h256 m_mixHash; mutable h256 m_seedHash; @@ -115,13 +98,6 @@ public: // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); - - /// Default value of the local work size. Also known as workgroup size. - static const unsigned defaultLocalWorkSize; - /// Default value of the global work size as a multiplier of the local work size - static const unsigned defaultGlobalWorkSizeMultiplier; - /// Default value of the milliseconds per global work size (per batch) - static const unsigned defaultMSPerBatch; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 00537c21a..c511978db 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; } EthashAux* dev::eth::EthashAux::s_this = nullptr; +const unsigned EthashProofOfWork::defaultLocalWorkSize = 64; +const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE +const unsigned EthashProofOfWork::defaultMSPerBatch = 0; +const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage(); + EthashAux::~EthashAux() { } @@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; } -Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) if (FullType dag = get()->m_fulls[_seedHash].lock()) return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { - return Ethash::Result{ ~h256(), h256() }; + return EthashProofOfWork::Result{ ~h256(), h256() }; } } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 132b9b436..d42e46d91 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -34,6 +34,47 @@ namespace eth struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; +/// Proof of work definition for Ethash. +struct EthashProofOfWork +{ + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + WorkPackage() = default; + WorkPackage(Ethash::BlockHeader const& _bh): + boundary(_bh.boundary()), + headerHash(_bh.hashWithout()), + seedHash(_bh.seedHash()) + {} + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; +}; + class EthashAux { public: @@ -46,7 +87,7 @@ public: LightAllocation(h256 const& _seedHash); ~LightAllocation(); bytesConstRef data() const; - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; ethash_light_t light; uint64_t size; }; @@ -55,7 +96,7 @@ public: { FullAllocation(ethash_light_t _light, ethash_callback_t _cb); ~FullAllocation(); - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; bytesConstRef data() const; uint64_t size() const { return ethash_full_dag_size(full); } ethash_full_t full; @@ -79,7 +120,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: EthashAux() {} diff --git a/libethcore/Farm.h b/libethcore/Farm.h index b69f8325a..c86b4804e 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -123,9 +123,9 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const + WorkingProgress const& miningProgress() const { - MiningProgress p; + WorkingProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); @@ -195,7 +195,7 @@ private: std::atomic m_isMining = {false}; mutable SharedMutex x_progress; - mutable MiningProgress m_progress; + mutable WorkingProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 03eba9880..90a5902c4 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,9 +36,9 @@ namespace dev namespace eth { -struct MineInfo: public MiningProgress {}; +struct MineInfo: public WorkingProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) +inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p) { _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp deleted file mode 100644 index 843db72c7..000000000 --- a/libethcore/ProofOfWork.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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 ProofOfWork.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "ProofOfWork.h" -#include "BlockInfo.h" -using namespace std; -using namespace dev; -using namespace eth; - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h deleted file mode 100644 index f55c54df6..000000000 --- a/libethcore/ProofOfWork.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 ProofOfWork.h - * @author Gav Wood - * @date 2014 - * - * Determines the PoW algorithm. - */ - -#pragma once - -#include -#include -#include "Common.h" -//#include "Ethash.h" -#include "BasicAuthority.h" - -namespace dev -{ -namespace eth -{ - -using ProofOfWork = BasicAuthority; - -} -} diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index 28381444e..137659dfc 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -25,6 +25,7 @@ #include #include +#include #include "Common.h" namespace dev @@ -34,28 +35,22 @@ namespace eth class BlockInfo; -class SealFace -{ -public: - virtual bool wouldSealHeader(BlockInfo const&) const { return true; } - virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; -}; - class SealEngineFace { public: + virtual std::string name() const = 0; + virtual unsigned revision() const = 0; + virtual unsigned sealFields() const = 0; + virtual bytes sealRLP() const = 0; + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; - virtual void onSealGenerated(std::function const& _f) = 0; - virtual void disable() {} - - // TODO: rename & generalise - virtual bool isMining() const { return false; } - virtual MiningProgress miningProgress() const { return MiningProgress(); } + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} protected: virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } @@ -66,5 +61,15 @@ private: std::unordered_map m_options; }; +template +class SealEngineBase: public SealEngineFace +{ +public: + std::string name() const override { return Sealer::name(); } + unsigned revision() const override { return Sealer::revision(); } + unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; } + bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); } +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 14b13b90d..aae8cbd10 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,12 +35,12 @@ #include #include #include -#include #include #include #include #include "GenesisInfo.h" #include "State.h" +#include "Utility.h" #include "Defaults.h" using namespace std; @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 1 +#define ETH_CATCH 0 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 @@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): + m_genesisState(_genesisState) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit // Initialise with the genesis as the last block on the longest chain. m_genesisBlock = _genesisBlock; m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); + m_genesisState = _genesisState; + + // remove the next line real soon. we don't need to be supporting this forever. + upgradeDatabase(_path, genesisHash()); if (open(_path, _we) != c_minorProtocolVersion) rebuild(_path, _p); @@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); - BlockInfo bi(b); + BlockInfo bi(&b); if (_prepPoW) - Ethash::prep(bi); + Ethash::ensurePrecomputed((unsigned)bi.number); if (bi.parentHash != lastHash) { @@ -351,7 +356,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; @@ -388,7 +393,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad, _ir); + block = verifyBlock(&_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) @@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& auto parentBlock = block(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; - clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); + clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); @@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(_block, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this); for (unsigned i = 0; i < s.pending().size(); ++i) { @@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db) try { cout << "block..." << flush; - BlockInfo bi = info(h); - cout << "details..." << flush; - BlockDetails bd = details(h); + BlockInfo bi(block(h)); + cout << "extras..." << flush; + details(h); cout << "state..." << flush; if (_db.exists(bi.stateRoot)) break; @@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +bytes BlockChain::headerData(h256 const& _hash) const { - VerifiedBlockRef res; - try - { - Strictness strictness = Strictness::CheckEverything; - if (~_ir & ImportRequirements::ValidNonce) - strictness = Strictness::IgnoreNonce; + if (_hash == m_genesisHash) + return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes(); - res.info.populate(_block, strictness); - res.info.verifyInternals(&_block); - } - catch (Exception& ex) { - ex << errinfo_phase(1); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; + ReadGuard l(x_blocks); + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + return BlockInfo::extractHeader(&it->second).data().toBytes(); } - RLP r(_block); - unsigned i = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_uncleIndex(i); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; - } - i = 0; - for (RLP const& tr: r[1]) + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + + if (d.empty()) { - bytesConstRef d = tr.data(); - try - { - res.transactions.push_back(Transaction(d, CheckTransaction::Everything)); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_transactionIndex(i); - ex << errinfo_transaction(d.toBytes()); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; + cwarn << "Couldn't find requested block:" << _hash; + return bytes(); } - res.block = bytesConstRef(&_block); - return res; + + noteUsed(_hash); + + WriteGuard l(x_blocks); + m_blocks[_hash].resize(d.size()); + memcpy(m_blocks[_hash].data(), d.data(), d.size()); + + return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes(); } +State BlockChain::genesisState(OverlayDB const& _db) +{ + State ret(_db, BaseState::Empty); + dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? + ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. + ret.m_previousBlock = BlockInfo(&m_genesisBlock); + return ret; +} + + + + + + + + + + + + + + + + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 638c9c3af..50965f2b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,6 +37,7 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" +#include "State.h" namespace std { @@ -86,6 +87,13 @@ enum { }; using ProgressCallback = std::function; +using StateDefinition = std::unordered_map; + +class VersionChecker +{ +public: + VersionChecker(std::string const& _dbPath, h256 const& _genesisHash); +}; /** * @brief Implements the blockchain database. All data this gives is disk-backed. @@ -94,7 +102,7 @@ using ProgressCallback = std::function; class BlockChain { public: - BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); ~BlockChain(); /// Attempt a database re-open. @@ -120,14 +128,17 @@ public: /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; - /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. - BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); } + /// Get the partial-header of a block (or the most recent mined if none given). Thread-safe. + BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); } BlockInfo info() const { return info(currentHash()); } /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. bytes block(h256 const& _hash) const; bytes block() const { return block(currentHash()); } - bytes oldBlock(h256 const& _hash) const; + + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes headerData(h256 const& _hash) const; + bytes headerData() const { return headerData(currentHash()); } /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. BlockDetails details(h256 const& _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } @@ -264,13 +275,16 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); - /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); - /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } -private: + /// Get a pre-made genesis State object. + State genesisState(OverlayDB const& _db); + + /// Verify block and prepare it for enactment + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + +protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); @@ -345,6 +359,7 @@ private: /// Genesis block info. h256 m_genesisHash; bytes m_genesisBlock; + std::unordered_map m_genesisState; ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; @@ -354,6 +369,88 @@ private: friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; +template +class FullBlockChain: public BlockChain +{ +public: + using BlockHeader = typename Sealer::BlockHeader; + + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path, _we, _p) + {} + + /// Get the header of a block (or the most recent mined if none given). Thread-safe. + typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } + typename Sealer::BlockHeader header() const { return header(currentHash()); } + + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + { + VerifiedBlockRef res; + + try + { + BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); + h.verifyInternals(_block); + h.verifyParent(header(h.parentHash)); + res.info = static_cast(h); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + if (_ir && ImportRequirements::UncleBasic) + for (auto const& uncle: r[2]) + { + try + { + BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + if (_ir && ImportRequirements::TransactionBasic) + for (RLP const& tr: r[1]) + { + bytesConstRef d = tr.data(); + try + { + res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None)); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_transactionIndex(i); + ex << errinfo_transaction(d.toBytes()); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + res.block = bytesConstRef(_block); + return res; + } +}; + std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); } diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 2cf2a7583..a59326b77 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const for (unsigned i = 0; i < itemCount; ++i) { - auto h = BlockInfo::headerHash(_r[i].data()); + auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) + switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; @@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const logNewBlock(h); if (m_state == SyncState::NewBlocks) { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); + BlockInfo bi(_r[i].data()); if (bi.number > maxUnknownNumber) { maxUnknownNumber = bi.number; @@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP con { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); + auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { - switch (host().bq().import(_r[0].data(), host().chain())) + switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b6c548c1f..6b400b236 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); } catch (...) { @@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() } } -ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) +ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. - h256 h = BlockInfo::headerHash(_block); + h256 h = BlockInfo::headerHashFromBlock(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; @@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::AlreadyKnown; } - // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { - // TODO: quick verify - bi.populate(_block); - bi.verifyInternals(_block); + // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer + // VERIFY: populates from the block and checks the block is internally coherent. + bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info; } catch (Exception const& _e) { @@ -218,7 +216,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! - if (_bc.isKnown(h)) + if (m_bc->isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; @@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else @@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; @@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad) return !m_readySet.empty(); } -void BlockQueue::tick(BlockChain const& _bc) +void BlockQueue::tick() { vector> todo; { @@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc) cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) - import(&b.second, _bc); + import(&b.second); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index b9e6f5b3b..97fca7c72 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -76,11 +76,13 @@ public: BlockQueue(); ~BlockQueue(); + void setChain(BlockChain const& _bc) { m_bc = &_bc; } + /// Import a block into the queue. - ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. - void tick(BlockChain const& _bc); + void tick(); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. @@ -138,6 +140,8 @@ private: void updateBad_WITH_LOCK(h256 const& _bad); void drainVerified_WITH_BOTH_LOCKS(); + BlockChain const* m_bc; ///< The blockchain into which our imports go. + mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. h256Hash m_readySet; ///< All blocks ready for chain import. diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 4e6d89243..eee4b98b7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -41,14 +40,44 @@ namespace js = json_spirit; #define ETH_CATCH 1 -std::unordered_map const& dev::eth::genesisState() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); +std::string CanonBlockChain::s_genesisStateJSON; + +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) +{ +} + +bytes CanonBlockChain::createGenesisBlock() +{ + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + SecureTrieDB state(&db); + state.init(); + dev::eth::commit(createGenesisState(), state); + stateRoot = state.root(); + } + + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +unordered_map CanonBlockChain::createGenesisState() { static std::unordered_map s_ret; if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(c_genesisInfo, val); + json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()) { u256 balance; @@ -68,53 +97,29 @@ std::unordered_map const& dev::eth::genesisState() return s_ret; } -// TODO: place Registry in here. - -std::unique_ptr CanonBlockChain::s_genesis; -boost::shared_mutex CanonBlockChain::x_genesis; -Nonce CanonBlockChain::s_nonce(u64(42)); - -bytes CanonBlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - SecureTrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - BlockChain(createGenesisBlock(), _path, _we, _pc) +void CanonBlockChain::setGenesisState(std::string const& _json) { + WriteGuard l(x_genesis); + s_genesisStateJSON = _json; + s_genesis.reset(); } -void CanonBlockChain::setGenesisNonce(Nonce const& _n) +void CanonBlockChain::setGenesisNonce(Nonce const& _n) { WriteGuard l(x_genesis); s_nonce = _n; s_genesis.reset(); } -BlockInfo const& CanonBlockChain::genesis() +Ethash::BlockHeader const& CanonBlockChain::genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); - s_genesis.reset(new BlockInfo); - s_genesis->populate(&gb); + s_genesis.reset(new Ethash::BlockHeader); + s_genesis->populate(&gb, CheckEverything); } return *s_genesis; } diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index c16479f0d..d79926703 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BlockDetails.h" #include "Account.h" @@ -45,7 +46,32 @@ std::unordered_map const& genesisState(); * @threadsafe * @todo Make not memory hog (should actually act as a cache and deallocate old entries). */ -class CanonBlockChain: public BlockChain +template +class CanonBlockChain: public FullBlockChain +{ +public: + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + ~CanonBlockChain() {} + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock() + { + RLPStream block(3); + block.appendList(Sealer::BlockHeader::Fields) + << h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string(); + bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP(); + block.appendRaw(sealFields, Sealer::BlockHeader::SealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); + } +}; + +template <> +class CanonBlockChain: public FullBlockChain { public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} @@ -53,22 +79,35 @@ public: ~CanonBlockChain() {} /// @returns the genesis block header. - static BlockInfo const& genesis(); + static Ethash::BlockHeader const& genesis(); /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static std::unordered_map createGenesisState(); + /// Alter the value of the genesis block's nonce. /// @warning Unless you're very careful, make sure you call this right at the start of the /// program, before anything has had the chance to use this class at all. static void setGenesisNonce(Nonce const& _n); + /// Alter all the genesis block's state by giving a JSON string with account details. + /// @TODO implement. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisState(std::string const&); + + // TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, + private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + static std::unique_ptr s_genesis; static Nonce s_nonce; + static std::string s_genesisStateJSON; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 918480263..ec37302a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -72,47 +72,43 @@ static const Addresses c_canaries = Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph }; -VersionChecker::VersionChecker(string const& _dbPath) +Client::Client(std::shared_ptr _gp): + Worker("eth", 0), + m_gp(_gp ? _gp : make_shared()) { - upgradeDatabase(_dbPath); } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Client(_extNet, make_shared(), _dbPath, _forceAction, _networkId) +void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId) { - startWorking(); -} + // Cannot be opened until after blockchain is open, since BlockChain may upgrade the database. + // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database + // until after the construction. + m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); + m_preMine = State(m_stateDB); + m_postMine = State(m_stateDB); + // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. + m_preMine = bc().genesisState(m_stateDB); -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth", 0), - m_vc(_dbPath), - m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), - m_gp(_gp), - m_stateDB(State::openDB(_dbPath, _forceAction)), - m_preMine(m_stateDB, BaseState::CanonGenesis), - m_postMine(m_stateDB) -{ - if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + m_bq.setChain(bc()); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_sealEngine = shared_ptr(Ethash::createSealEngine()); - m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); + bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_gp->update(m_bc); + if (_forceAction == WithExisting::Rescue) + m_bc.rescue(m_stateDB); + + m_gp->update(bc()); - auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); + auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId)); m_host = host; _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common if (_dbPath.size()) Defaults::setDBPath(_dbPath); doWork(); - startWorking(); } @@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000) this_thread::sleep_for(std::chrono::milliseconds(500)); - return m_bq.import(&_block, bc(), _isSafe); + return m_bq.import(&_block, _isSafe); } tuple Client::syncQueue(unsigned _max) { stopWorking(); - return m_bc.sync(m_bq, m_stateDB, _max); + return bc().sync(m_bq, m_stateDB, _max); } void Client::onBadBlock(Exception& _ex) const @@ -294,7 +290,7 @@ void Client::startedWorking() clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -309,7 +305,7 @@ void Client::doneWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -328,7 +324,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.disable(); + m_sealEngine->cancelGeneration(); { WriteGuard l(x_postMine); @@ -340,10 +336,10 @@ void Client::killChain() m_working = State(); m_stateDB = OverlayDB(); - m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); - m_bc.reopen(Defaults::dbPath(), WithExisting::Kill); + m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); + bc().reopen(Defaults::dbPath(), WithExisting::Kill); - m_preMine = State(m_stateDB, BaseState::CanonGenesis); + m_preMine = bc().genesisState(m_stateDB); m_postMine = State(m_stateDB); } @@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); - auto receipts = m_bc.receipts(_block).receipts; + auto d = bc().info(_block); + auto receipts = bc().receipts(_block).receipts; Guard l(x_filtersWatches); io_changed.insert(ChainChangedFilter); @@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable) startMining(); } -MiningProgress Client::miningProgress() const +bool Client::isMining() const { - if (m_farm.isMining()) - return m_farm.miningProgress(); - return MiningProgress(); + return Ethash::isWorking(m_sealEngine.get()); +} + +WorkingProgress Client::miningProgress() const +{ + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()); + return WorkingProgress(); } uint64_t Client::hashrate() const { - if (m_farm.isMining()) - return m_farm.miningProgress().rate(); + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()).rate(); return 0; } @@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -ProofOfWork::WorkPackage Client::getWork() -{ - // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. - // this will be reset as soon as a new block arrives, allowing more transactions to be processed. - bool oldShould = shouldServeWork(); - m_lastGetWork = chrono::system_clock::now(); - - if (!m_mineOnBadChain && isChainBad()) - return ProofOfWork::WorkPackage(); - - // if this request has made us bother to serve work, prep it now. - if (!oldShould && shouldServeWork()) - onPostStateChanged(); - else - // otherwise, set this to true so that it gets prepped next time. - m_remoteWorking = true; - return ProofOfWork::package(m_miningInfo); -} - -bool Client::submitWork(ProofOfWork::Solution const& _solution) -{ - bytes newBlock; - DEV_WRITE_GUARDED(x_working) - if (!m_working.completeMine(_solution)) - return false; - - DEV_READ_GUARDED(x_working) - { - DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; - newBlock = m_working.blockData(); - } - - // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. - m_bq.import(&newBlock, m_bc, true); - - return true; -} - unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; @@ -553,7 +515,7 @@ void Client::syncBlockQueue() ImportRoute ir; unsigned count; Timer t; - tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); if (count) @@ -577,7 +539,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; DEV_WRITE_GUARDED(x_working) - tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp); if (newPendingReceipts.empty()) return; @@ -590,7 +552,7 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restart mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& h: _ir.deadBlocks) { clog(ClientTrace) << "Dead block:" << h; - for (auto const& t: m_bc.transactions(h)) + for (auto const& t: bc().transactions(h)) { clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, IfDropped::Retry); @@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir) newPreMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + preChanged = newPreMine.sync(bc()); if (preChanged || m_postMine.address() != m_preMine.address()) { @@ -700,7 +662,7 @@ void Client::rejigMining() { clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) - m_working.commitToMine(m_bc, m_extraData); + m_working.commitToMine(bc(), m_extraData); DEV_READ_GUARDED(x_working) { DEV_WRITE_GUARDED(x_postMine) @@ -709,10 +671,10 @@ void Client::rejigMining() } if (m_wouldMine) - m_farm.sealBlock(m_miningInfo); + m_sealEngine->generateSeal(m_miningInfo); } if (!m_wouldMine) - m_farm.disable(); + m_sealEngine->cancelGeneration(); } void Client::noteChanged(h256Hash const& _filters) @@ -768,7 +730,7 @@ void Client::tick() { m_report.ticks++; checkWatchGarbage(); - m_bq.tick(m_bc); + m_bq.tick(); m_lastTick = chrono::system_clock::now(); if (m_report.ticks == 15) clog(ClientTrace) << activityReport(); @@ -792,7 +754,7 @@ void Client::checkWatchGarbage() uninstallWatch(i); // blockchain GC - m_bc.garbageCollect(); + bc().garbageCollect(); m_lastGarbageCollection = chrono::system_clock::now(); } @@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const try { State ret(m_stateDB); - ret.populateFromChain(m_bc, _block); + ret.populateFromChain(bc(), _block); return ret.fromPending(_txi); } catch (Exception& ex) @@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const try { State ret(m_stateDB); - PopulationStatistics s = ret.populateFromChain(m_bc, _block); + PopulationStatistics s = ret.populateFromChain(bc(), _block); if (o_stats) swap(s, *o_stats); return ret; @@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const auto h = m_host.lock(); return h ? h->status() : SyncStatus(); } + +bool Client::submitSealed(bytes const& _header) +{ + DEV_WRITE_GUARDED(x_working) + if (!m_working.sealBlock(_header)) + return false; + + bytes newBlock; + DEV_READ_GUARDED(x_working) + { + DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + newBlock = m_working.blockData(); + } + + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. + return m_bq.import(&newBlock, true) == ImportResult::Success; +} + + + + + + + + + + + + + + +std::tuple EthashClient::getEthashWork() +{ + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); + m_lastGetWork = chrono::system_clock::now(); + + if (!m_mineOnBadChain && isChainBad()) + return std::tuple(); + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; + Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + return std::tuple(bh.boundary(), bh.hashWithout(), bh.seedHash()); +} + +bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce) +{ + Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce); + return true; +} + diff --git a/libethereum/Client.h b/libethereum/Client.h index 9ae7c7e09..73609bd71 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -60,12 +60,6 @@ enum ClientWorkState Deleted }; -class VersionChecker -{ -public: - VersionChecker(std::string const& _dbPath); -}; - struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; @@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); /** * @brief Main API hub for interfacing with Ethereum. + * Not to be used directly - subclass. */ class Client: public ClientBase, Worker { public: /// New-style Constructor. - explicit Client( - p2p::Host* _host, - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); - - explicit Client( - p2p::Host* _host, - std::shared_ptr _gpForAdoption, // pass it in with new. - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); + /// Any final derived class's constructor should make sure they call init(). + explicit Client(std::shared_ptr _gpForAdoption); /// Destructor. virtual ~Client(); @@ -129,7 +112,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. - CanonBlockChain const& blockChain() const { return m_bc; } + BlockChain const& blockChain() const { return bc(); } /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. @@ -176,26 +159,16 @@ public: /// NOT thread-safe void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? - bool isMining() const override { return m_farm.isMining(); } + bool isMining() const override; /// Are we mining now? bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MiningProgress miningProgress() const override; + WorkingProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); - /// Update to the latest transactions and get hash of the current block to be mined minus the - /// nonce (the 'work hash') and the difficulty to be met. - virtual ProofOfWork::WorkPackage getWork() override; - - /** @brief Submit the proof for the proof-of-work. - * @param _s A valid solution. - * @return true if the solution was indeed valid and accepted. - */ - virtual bool submitWork(ProofOfWork::Solution const& _proof) override; - // Debug stuff: DownloadMan const* downloadMan() const; @@ -218,12 +191,20 @@ public: /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } /// Rewind to a prior head. - void rewind(unsigned _n) { m_bc.rewind(_n); } + void rewind(unsigned _n) { bc().rewind(_n); } + /// Rescue the chain. + void rescue() { bc().rescue(m_stateDB); } + /// Get the seal engine. + SealEngineFace* sealEngine() const { return m_sealEngine.get(); } protected: + /// Perform critical setup functions. + /// Must be called in the constructor of the finally derived class. + void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); + /// InterfaceStub methods - virtual BlockChain& bc() override { return m_bc; } - virtual BlockChain const& bc() const override { return m_bc; } + virtual BlockChain& bc() override = 0; + virtual BlockChain const& bc() const override = 0; /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. @@ -245,7 +226,10 @@ protected: /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. void noteChanged(h256Hash const& _filters); -private: + /// Submit + bool submitSealed(bytes const& _s); + +protected: /// Called when Worker is starting. void startedWorking() override; @@ -291,8 +275,6 @@ private: /// @warning May be called from any thread. void onBadBlock(Exception& _ex) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -339,5 +321,64 @@ private: bytes m_extraData; }; +template +class SpecialisedClient: public Client +{ +public: + explicit SpecialisedClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): + Client(_gpForAdoption), + m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }) + { + m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSealGenerated([=](bytes const& header){ + return this->submitSealed(header); + }); + init(_host, _dbPath, _forceAction, _networkId); + } + + /// Get the object representing the current canonical blockchain. + CanonBlockChain const& blockChain() const { return m_bc; } + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } + +protected: + CanonBlockChain m_bc; ///< Maintains block database. +}; + +class EthashClient: public SpecialisedClient +{ +public: + /// Trivial forwarding constructor. + explicit EthashClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + + /// Update to the latest transactions and get hash of the current block to be mined minus the + /// nonce (the 'work hash') and the difficulty to be met. + virtual std::tuple getEthashWork() override; + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ + virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } +}; + } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f463b0195..769880269 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const auto bl = bc().block(_blockHash); RLP b(bl); if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); + return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData); else return BlockInfo(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 82f03def0..874f10548 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -156,9 +156,7 @@ public: virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } - virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } - virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } - virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } + virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 973433af9..213e7fb26 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" @@ -207,12 +207,12 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual ProofOfWork::WorkPackage getWork() = 0; + virtual std::tuple getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); } /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; + virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); } /// Check the progress of the mining. - virtual MiningProgress miningProgress() const = 0; + virtual WorkingProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1656109a9..ee2078a07 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } -OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) +OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; @@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) boost::filesystem::remove_all(path + "/state"); } - path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); + path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); ldb::Options o; @@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("beginning of Genesis construction.", true); - if (_bs == BaseState::CanonGenesis) - { - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); - - paranoia("after DB commit of Genesis construction.", true); - m_previousBlock = CanonBlockChain::genesis(); - } - else - m_previousBlock.clear(); - - resetCurrent(); - - assert(m_state.root() == m_previousBlock.stateRoot); + m_previousBlock.clear(); + m_currentBlock.clear(); +// assert(m_state.root() == m_previousBlock.stateRoot); paranoia("end of normal construction.", true); } @@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip; - bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip, _ir); + BlockInfo bip(_bc.block(bi.parentHash)); + sync(_bc, bi.parentHash, bip); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; - auto vb = BlockChain::verifyBlock(b); + auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); t.restart(); - enact(vb, _bc, _ir); + enact(vb, _bc); ret.enact = t.elapsed(); } else @@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi, _ir); + sync(_bc, _h, bi); } return ret; @@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ void State::commit() { - m_touched += dev::eth::commit(m_cache, m_db, m_state); + m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } @@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) +bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi) { - (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -355,7 +342,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor { cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; - cwarn << "Bailing."; + cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); } m_previousBlock = bi; @@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) { #if ETH_TIMED_ENACTMENTS Timer t; @@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _ir); + auto ret = enact(_block, _bc); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire RLP rlp(_block); cleanup(false); - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal); m_currentBlock = bi; m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); @@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) { DEV_TIMED_FUNCTION_ABOVE(500); @@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = _block.info; m_currentBlock.noteDirty(); + m_currentBlock = _block.info; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } @@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + // IgnoreSeal since it's a VerifiedBlock. + BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; if (!_bc.isKnown(uncle.parentHash)) @@ -829,6 +817,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { + (void)_bc; + /* commitToMine(_bc); // Update difficulty according to timestamp. @@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out(), std::function(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) { cwarn << "Bad block: " << _e.what(); } - +*/ return false; } @@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) for (auto const& u: us) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { - BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithProof); + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); ++unclesCount; - uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) break; } @@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) m_committedToMine = true; } -void State::completeMine() +bool State::sealBlock(bytesConstRef _header) { - cdebug << "Completing mine!"; + if (!m_committedToMine) + return false; + + cdebug << "Sealing block!"; // Got it! // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithProof); + ret.appendRaw(_header); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); - m_currentBlock.noteDirty(); + m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; -/* StructuredLogger::minedNewBlock( + // TODO: move into Sealer + StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.proof.nonce.abridged(), + "", // Can't give the nonce here. "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - );*/ + ); // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. @@ -989,6 +982,8 @@ void State::completeMine() m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; + + return true; } bool State::addressInUse(Address _id) const diff --git a/libethereum/State.h b/libethereum/State.h index f6a8471ea..805215ee5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "Account.h" @@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati enum class BaseState { PreExisting, - Empty, - CanonGenesis + Empty }; enum class Permanence @@ -104,6 +102,7 @@ class State friend class dev::test::ImportTest; friend class dev::test::StateLoader; friend class Executive; + friend class BlockChain; public: /// Default constructor; creates with a blank database prepopulated with the genesis block. @@ -125,7 +124,7 @@ public: ~State(); /// Construct state object from arbitrary point in blockchain. - PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None); /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. @@ -133,8 +132,8 @@ public: Address address() const { return m_ourAddress; } /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. - static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust); - static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } + static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); } OverlayDB const& db() const { return m_db; } OverlayDB& db() { return m_db; } @@ -163,22 +162,20 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. - template - bool completeMine(typename PoW::Solution const& _result) - { - if (!m_committedToMine) - return false; - - m_currentBlock.proof = _result; - if (!PoW::verify(m_currentBlock)) - return false; - -// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - - completeMine(); - - return true; - } + /// TODO: verify it prior to calling this. + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * while (notYetMined) + * { + * // lock + * commitToMine(_blockChain); // will call uncommitToMine if a repeat. + * completeMine(); + * // unlock + * @endcode + */ + bool sealBlock(bytes const& _header) { return sealBlock(&_header); } + bool sealBlock(bytesConstRef _header); /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. @@ -295,11 +292,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); + bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -313,19 +310,6 @@ public: void resetCurrent(); private: - /** Commit to DB and build the final block if the previous call to mine()'s result is completion. - * Typically looks like: - * @code - * while (notYetMined) - * { - * // lock - * commitToMine(_blockChain); // will call uncommitToMine if a repeat. - * completeMine(); - * // unlock - * @endcode - */ - void completeMine(); - /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -340,7 +324,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -386,7 +370,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, SecureTrieDB& _state) { AddressHash ret; for (auto const& i: _cache) @@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, } else { - SecureTrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); @@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, if (i.second.isFreshCode()) { h256 ch = sha3(i.second.code()); - _db.insert(ch, &i.second.code()); + _state.db()->insert(ch, &i.second.code()); s << ch; } else diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index e02012cd5..1b97f82e7 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args) return m_data; } -void dev::eth::upgradeDatabase(std::string const& _basePath) +void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash) { std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath; @@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath) { auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; - auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash; string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(databaseVersion); diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 0dfe8509b..df48269ec 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -42,7 +43,7 @@ namespace eth */ bytes parseData(std::string const& _args); -void upgradeDatabase(std::string const& _basePath); +void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash); } } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 7d63ed165..15d39bded 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); -#if ETH_USING_ETHASH // TODO: move into ProofOfWork. - res["nonce"] = toJS(_bi.proof.nonce); - res["seedHash"] = toJS(_bi.proofCache()); -#endif +// res["nonce"] = toJS(_bi.proof.nonce); +// res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..624a73e54 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. +template +Json::Value toJson(BlockHeaderPolished const& _bh) +{ + Json::Value res; + if (_bh) + { + res = toJson(static_cast(_bh)); + for (auto const& i: _bh.jsInfo()) + res[i.first] = i.second; + } + return res; +} + } namespace shh diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 1743882e5..061b5ae79 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -24,7 +24,6 @@ #include #include "../JsonSpiritHeaders.h" #include -#include #include #include #include "../TestHelper.h" @@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - Ethash::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 452163061..e3f8ac29f 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. From f693ac0cc4c484cf58d0f763c02c27f4bc7636fc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:29:03 +0200 Subject: [PATCH 076/113] All fields of BlockInfo now private. --- alethzero/MainWin.cpp | 34 +++--- ethminer/MinerAux.h | 4 +- evmjit/libevmjit-cpp/JitVM.cpp | 6 +- evmjit/libevmjit/RuntimeManager.cpp | 6 +- exp/main.cpp | 6 +- libethcore/BasicAuthority.cpp | 8 +- libethcore/BlockInfo.cpp | 104 ++++++++--------- libethcore/BlockInfo.h | 91 +++++++++------ libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 40 +++---- libethcore/EthashAux.cpp | 2 +- libethereum/BasicGasPricer.cpp | 6 +- libethereum/BlockChain.cpp | 78 +++++-------- libethereum/BlockChain.h | 2 +- libethereum/BlockChainSync.cpp | 6 +- libethereum/BlockQueue.cpp | 50 ++++---- libethereum/Executive.cpp | 10 +- libethereum/State.cpp | 133 +++++++++++----------- libethereum/State.h | 2 +- libevm/ExtVMFace.h | 4 +- libevm/VM.cpp | 10 +- libtestutils/BlockChainLoader.cpp | 2 +- libweb3jsonrpc/JsonHelper.cpp | 22 ++-- test/TestHelper.cpp | 6 +- test/libethereum/ClientBase.cpp | 18 +-- test/libethereum/blockchain.cpp | 78 ++++++------- test/libethereum/genesis.cpp | 2 +- test/libevm/vm.cpp | 12 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- third/MainWin.cpp | 2 +- 30 files changed, 378 insertions(+), 370 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2ee8928f5..ad8f5528c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,7 +189,7 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; @@ -1629,7 +1629,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1706,7 +1706,7 @@ void Main::on_blocks_currentItemChanged() if (item->data(Qt::UserRole + 1).isNull()) { char timestamp[64]; - time_t rawTime = (time_t)(uint64_t)info.timestamp; + time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; s << "

#" << info.number; @@ -1714,7 +1714,7 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; - s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "" << "
"; + s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; @@ -1724,7 +1724,7 @@ void Main::on_blocks_currentItemChanged() { auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; - s << "
Parent: " << info.parentHash << "" << "
"; + s << "
Parent: " << info.parentHash() << "" << "
"; } else { @@ -1732,20 +1732,20 @@ void Main::on_blocks_currentItemChanged() s << "
Parent: It was a virgin birth
"; } // s << "
Bloom: " << details.bloom << ""; - if (!!info.logBloom) - s << "
Log Bloom: " << info.logBloom << "
"; + if (!!info.logBloom()) + s << "
Log Bloom: " << info.logBloom() << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; - s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Parent: " << uncle.parentHash() << "" << ""; s << line << "Number: " << uncle.number << "" << ""; - s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; @@ -1754,20 +1754,20 @@ void Main::on_blocks_currentItemChanged() auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } - if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; + if (info.parentHash()) + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; else s << "
Pre: Nothing is before Phil" << "
"; - s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; + s << "
Receipts: @" << info.receiptsRoot() << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Post: " << info.stateRoot() << "" << "
"; s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } @@ -1807,7 +1807,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 61fde605d..0d227b1ef 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -398,8 +398,8 @@ private: void doInitDAG(unsigned _n) { BlockInfo bi; - bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; + bi.number() = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 2fb2a0e67..4e1fb66ea 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -24,7 +24,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index d48b64bb1..b2c15d7ae 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,7 +1,7 @@ #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" #include "Stack.h" @@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; + case RuntimeData::Timestamp: return "block.timestamp()"; case RuntimeData::Code: return "code.ptr"; case RuntimeData::CodeSize: return "code.size"; } diff --git a/exp/main.cpp b/exp/main.cpp index 4a35068f1..0b740e526 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,8 +85,8 @@ int main() BlockInfo bi; bi.difficulty = c_genesisDifficulty; bi.gasLimit = c_genesisGasLimit; - bi.number = 1; - bi.parentHash = sha3("parentHash"); + bi.number() = 1; + bi.parentHash() = sha3("parentHash"); bytes sealedData; @@ -329,7 +329,7 @@ int main() mine(s, bc, se); bytes minedBlock = s.blockData(); - cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot(); bc.import(minedBlock, stateDB); cnote << bc; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 22da67080..7ef3dd21e 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -44,19 +44,19 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri m_sig = _header[BlockInfo::BasicFields].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); BOOST_THROW_EXCEPTION(ex); } } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 64961bc40..266f57cc8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -BlockInfo::BlockInfo(): timestamp(Invalid256) +BlockInfo::BlockInfo(): m_timestamp(Invalid256) { } @@ -45,26 +45,26 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, void BlockInfo::clear() { - parentHash = h256(); - sha3Uncles = EmptyListSHA3; - coinbaseAddress = Address(); - stateRoot = EmptyTrie; - transactionsRoot = EmptyTrie; - receiptsRoot = EmptyTrie; - logBloom = LogBloom(); - difficulty = 0; - number = 0; - gasLimit = 0; - gasUsed = 0; - timestamp = 0; - extraData.clear(); + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_coinbaseAddress = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = 0; + m_extraData.clear(); noteDirty(); } h256 const& BlockInfo::boundary() const { - if (!m_boundary && difficulty) - m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); + if (!m_boundary && m_difficulty) + m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty); return m_boundary; } @@ -81,8 +81,8 @@ h256 const& BlockInfo::hashWithout() const void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << gasLimit << gasUsed << timestamp << extraData; + _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; } h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) @@ -110,19 +110,19 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { - parentHash = _header[field = 0].toHash(RLP::VeryStrict); - sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); - coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); - stateRoot = _header[field = 3].toHash(RLP::VeryStrict); - transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); - receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); - logBloom = _header[field = 6].toHash(RLP::VeryStrict); - difficulty = _header[field = 7].toInt(); - number = _header[field = 8].toInt(); - gasLimit = _header[field = 9].toInt(); - gasUsed = _header[field = 10].toInt(); - timestamp = _header[field = 11].toInt(); - extraData = _header[field = 12].toBytes(); + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toInt(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toInt(); + m_extraData = _header[field = 12].toBytes(); } catch (Exception const& _e) { @@ -130,11 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) throw; } - if (number > ~(unsigned)0) + if (m_number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing && gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); + if (_s != CheckNothing && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -147,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); - if (transactionsRoot != expectedRoot) + if (m_transactionsRoot != expectedRoot) { MemoryDB tm; GenericTrieDB transactionsTrie(&tm); @@ -172,52 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) cdebug << toHex(t); - BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot)); + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); - if (sha3Uncles != sha3(root[2].data())) + if (m_sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } void BlockInfo::populateFromParent(BlockInfo const& _parent) { - stateRoot = _parent.stateRoot; - number = _parent.number + 1; - gasLimit = selectGasLimit(_parent); - gasUsed = 0; - difficulty = calculateDifficulty(_parent); - parentHash = _parent.hash(); + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_gasLimit = selectGasLimit(_parent); + m_gasUsed = 0; + m_difficulty = calculateDifficulty(_parent); + m_parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return c_genesisGasLimit; else // target minimum of 3141592 - if (_parent.gasLimit < c_genesisGasLimit) - return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + if (_parent.m_gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return (u256)c_genesisDifficulty; else - return max(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor))); + return max(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); } void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check timestamp is after previous timestamp. - if (parentHash) + if (m_parentHash) { - if (timestamp <= _parent.timestamp) + if (m_timestamp <= _parent.m_timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); - if (number != _parent.number + 1) + if (m_number != _parent.m_number + 1) BOOST_THROW_EXCEPTION(InvalidNumber()); } } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b00fa73fb..67a5397f4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -81,21 +81,6 @@ struct BlockInfo public: static const unsigned BasicFields = 13; - // TODO: make them all private! - h256 parentHash; - h256 sha3Uncles; - Address coinbaseAddress; - h256 stateRoot; - h256 transactionsRoot; - h256 receiptsRoot; - LogBloom logBloom; - u256 difficulty; // TODO: pull out into BlockHeader - u256 number; - u256 gasLimit; - u256 gasUsed; - u256 timestamp = Invalid256; - bytes extraData; - BlockInfo(); explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} @@ -104,23 +89,23 @@ public: static h256 headerHashFromBlock(bytesConstRef _block); static RLP extractHeader(bytesConstRef _block); - explicit operator bool() const { return timestamp != Invalid256; } + explicit operator bool() const { return m_timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { - return parentHash == _cmp.parentHash && - sha3Uncles == _cmp.sha3Uncles && - coinbaseAddress == _cmp.coinbaseAddress && - stateRoot == _cmp.stateRoot && - transactionsRoot == _cmp.transactionsRoot && - receiptsRoot == _cmp.receiptsRoot && - logBloom == _cmp.logBloom && - difficulty == _cmp.difficulty && - number == _cmp.number && - gasLimit == _cmp.gasLimit && - gasUsed == _cmp.gasUsed && - timestamp == _cmp.timestamp && - extraData == _cmp.extraData; + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_coinbaseAddress == _cmp.coinbaseAddress() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } @@ -132,6 +117,31 @@ public: u256 selectGasLimit(BlockInfo const& _parent) const; h256 const& boundary() const; + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); } + void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + + Address const& coinbaseAddress() const { return m_coinbaseAddress; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& timestamp() const { return m_timestamp; } + bytes const& extraData() const { return m_extraData; } + + u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader + /// sha3 of the header only. h256 const& hashWithout() const; h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } @@ -145,6 +155,21 @@ protected: mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + h256 m_parentHash; + h256 m_sha3Uncles; + Address m_coinbaseAddress; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + u256 m_number; + u256 m_gasLimit; + u256 m_gasUsed; + u256 m_timestamp = Invalid256; + bytes m_extraData; + + u256 m_difficulty; // TODO: pull out into BlockHeader + private: mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty @@ -152,9 +177,9 @@ private: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp; + _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); return _out; } @@ -191,7 +216,7 @@ public: // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { - if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); BlockInfoSub::verifyParent(_parent); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 499854584..05cc45280 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -124,7 +124,7 @@ static void badBlockInfo(BlockInfo const& _bi, string const& _err) ss << c_space << endl; ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_space << endl; - string bin = toString(_bi.number); + string bin = toString(_bi.number()); ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; ss << c_space << endl; ss << c_line; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 128822b80..ee483aa8b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ namespace eth h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); + m_seedHash = EthashAux::seedHash((unsigned)m_number); return m_seedHash; } @@ -72,7 +72,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_nonce(m_nonce); @@ -81,42 +81,42 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } if (_s != CheckNothing) { - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + if (m_difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) ); - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + if (m_gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) ); - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + if (m_number && m_extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size()))); } } void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) { // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + if (m_difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty)); - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); + if (m_gasLimit < c_minGasLimit || + m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor || + m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)); } void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) @@ -126,7 +126,7 @@ void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) bool Ethash::BlockHeaderRaw::preVerify() const { - if (number >= ETHASH_EPOCH_LENGTH * 2048) + if (m_number >= ETHASH_EPOCH_LENGTH * 2048) return false; bool ret = !!ethash_quick_check_difficulty( @@ -162,7 +162,7 @@ bool Ethash::BlockHeaderRaw::verify() const cwarn << "headerHash:" << hashWithout(); cwarn << "nonce:" << m_nonce; cwarn << "mixHash:" << m_mixHash; - cwarn << "difficulty:" << difficulty; + cwarn << "difficulty:" << m_difficulty; cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; @@ -290,7 +290,7 @@ public: m_farm.setWork(m_sealing); m_farm.start(m_sealer); m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number); + Ethash::ensurePrecomputed((unsigned)_bi.number()); } void onSealGenerated(std::function const& _f) override { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index c511978db..763bea417 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,7 +63,7 @@ EthashAux* EthashAux::get() uint64_t EthashAux::cacheSize(BlockInfo const& _header) { - return ethash_get_cachesize((uint64_t)_header.number); + return ethash_get_cachesize((uint64_t)_header.number()); } uint64_t EthashAux::dataSize(uint64_t _blockNumber) diff --git a/libethereum/BasicGasPricer.cpp b/libethereum/BasicGasPricer.cpp index 145d23594..b957966f8 100644 --- a/libethereum/BasicGasPricer.cpp +++ b/libethereum/BasicGasPricer.cpp @@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; h256 p = _bc.currentHash(); - m_gasPerBlock = _bc.info(p).gasLimit; + m_gasPerBlock = _bc.info(p).gasLimit(); map dist; u256 total = 0; @@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc) while (c < 1000 && p) { BlockInfo bi = _bc.info(p); - if (bi.transactionsRoot != EmptyTrie) + if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); @@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc) i++; } } - p = bi.parentHash; + p = bi.parentHash(); ++c; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aae8cbd10..b696c77bd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) { try { BlockInfo d(bytesConstRef(it->value())); - _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; + _out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; } catch (...) { cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); @@ -293,11 +293,11 @@ void BlockChain::rebuild(std::string const& _path, std::function parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1); + cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); return; } lastHash = bi.hash(); @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -461,21 +461,21 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Work out its number as the parent's number + 1 - if (!isKnown(_block.info.parentHash)) + if (!isKnown(_block.info.parentHash())) { - clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash(); // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_block.info.parentHash); + auto pd = details(_block.info.parentHash()); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_block.info.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; + auto parentBlock = block(_block.info.parentHash()); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash()); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number(); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -483,9 +483,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Check it's not crazy - if (_block.info.timestamp > (u256)time(0)) + if (_block.info.timestamp() > (u256)time(0)) { - clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } @@ -543,9 +543,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_block.info.parentHash); + details(_block.info.parentHash()); DEV_WRITE_GUARDED(x_details) - m_details[_block.info.parentHash].children.push_back(_block.info.hash()); + m_details[_block.info.parentHash()].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); @@ -554,9 +554,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp())); - extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); @@ -585,10 +585,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif - // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; h256 common; @@ -599,7 +599,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash()); route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be @@ -630,15 +630,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Collate logs into blooms. h256s alteredBlooms; { - LogBloom blockBloom = tbi.logBloom; - blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); + LogBloom blockBloom = tbi.logBloom(); + blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref())); // Pre-memoize everything we need before locking x_blocksBlooms - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) blocksBlooms(chunkId(level, index / c_bloomIndexSize)); WriteGuard l(x_blocksBlooms); - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) { unsigned i = index / c_bloomIndexSize; unsigned o = index % c_bloomIndexSize; @@ -661,23 +661,23 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& ReadGuard l1(x_blocksBlooms); for (auto const& h: alteredBlooms) extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); - extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); + extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); } // FINALLY! change our best hash. { newLastBlockHash = _block.info.hash(); - newLastBlockNumber = (unsigned)_block.info.number; + newLastBlockNumber = (unsigned)_block.info.number(); } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; #if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif } @@ -750,7 +750,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& checkBest = t.elapsed(); if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number(); cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; @@ -758,7 +758,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; cnote << " " << _block.transactions.size() << " transactions"; - cnote << " " << _block.info.gasUsed << " gas used"; + cnote << " " << _block.info.gasUsed() << " gas used"; } #endif @@ -861,7 +861,7 @@ void BlockChain::rescue(OverlayDB& _db) cout << "extras..." << flush; details(h); cout << "state..." << flush; - if (_db.exists(bi.stateRoot)) + if (_db.exists(bi.stateRoot())) break; } catch (...) {} @@ -1233,19 +1233,3 @@ State BlockChain::genesisState(OverlayDB const& _db) return ret; } - - - - - - - - - - - - - - - - diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50965f2b6..3ff85c8a6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -391,7 +391,7 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash)); + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index a59326b77..64d1bb197 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr _peer) unsigned BlockChainSync::estimatedHashes() const { BlockInfo block = host().chain().info(); - time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp(); time_t now = time(0); unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) @@ -220,9 +220,9 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); - if (bi.number > maxUnknownNumber) + if (bi.number() > maxUnknownNumber) { - maxUnknownNumber = bi.number; + maxUnknownNumber = bi.number(); maxUnknown = h; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6b400b236..c9ee4c1cf 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,8 +101,8 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.sha3Uncles = work.hash; - bi.parentHash = work.parentHash; + bi.setSha3Uncles(work.hash); + bi.setParentHash(work.parentHash); m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.sha3Uncles == work.hash) + if (it->verified.info.sha3Uncles() == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,11 +136,11 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash) { // we're next! m_verifying.pop_front(); - if (m_knownBad.count(res.verified.info.parentHash)) + if (m_knownBad.count(res.verified.info.parentHash())) { m_readySet.erase(res.verified.info.hash()); m_knownBad.insert(res.verified.info.hash()); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.sha3Uncles == work.hash) + if (i.verified.info.sha3Uncles() == work.hash) { i = move(res); goto OK; @@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() { while (!m_verifying.empty() && !m_verifying.front().blockData.empty()) { - if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + if (m_knownBad.count(m_verifying.front().verified.info.parentHash())) { m_readySet.erase(m_verifying.front().verified.info.hash()); m_knownBad.insert(m_verifying.front().verified.info.hash()); @@ -213,7 +213,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) return ImportResult::Malformed; } - clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash(); // Check block doesn't already exist first! if (m_bc->isKnown(h)) @@ -227,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // Check it's not in the future (void)_isOurs; - if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) + if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/) { - m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); + m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes()))); char buf[24]; - time_t bit = (unsigned)bi.timestamp; + time_t bit = (unsigned)bi.timestamp(); if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails - clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp() << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); + m_difficulty += bi.difficulty(); + bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash()); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. - if (m_knownBad.count(bi.parentHash)) + if (m_knownBad.count(bi.parentHash())) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash())) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; - m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash(); + m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_unknownCount++; return ImportResult::UnknownParent; @@ -268,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash(), _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_knownCount++; noteReady_WITH_LOCK(h); @@ -295,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::vector oldVerified; swap(m_verified, oldVerified); for (auto& b: oldVerified) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash())) { m_knownBad.insert(b.verified.info.hash()); m_readySet.erase(b.verified.info.hash()); @@ -321,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles())) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles(); m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); @@ -460,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; + m_drainingDifficulty += bs.verified.info.difficulty(); m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 866c9c8f9..e58e1a8c6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), + m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)), m_depth(_level) {} @@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction) // Avoid transactions that would take us beyond the block gas limit. u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) + if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit()) { - clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; - BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas())); } // Check gas cost is enough. @@ -403,7 +403,7 @@ void Executive::finalize() m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); - m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); + m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned); // Suicides... if (m_ext) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ee2078a07..64daaf5f8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -105,7 +105,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock.clear(); m_currentBlock.clear(); -// assert(m_state.root() == m_previousBlock.stateRoot); +// assert(m_state.root() == m_previousBlock.stateRoot()); paranoia("end of normal construction.", true); } @@ -123,16 +123,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& auto b = _bc.block(_h); BlockInfo bi(b); - if (bi.number) + if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + BlockInfo bip(_bc.block(bi.parentHash())); + sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. - m_ourAddress = bi.coinbaseAddress; + m_ourAddress = bi.coinbaseAddress(); Timer t; auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); @@ -338,9 +338,9 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - if (m_db.lookup(bi.stateRoot).empty()) + if (m_db.lookup(bi.stateRoot()).empty()) { - cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; + cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); @@ -357,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash()); // push back for later replay. - bi.populate(_bc.block(bi.parentHash)); // move to parent. + bi.populate(_bc.block(bi.parentHash())); // move to parent. } m_previousBlock = bi; @@ -402,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif // Check family: - BlockInfo biParent = _bc.info(_block.info.parentHash); + BlockInfo biParent = _bc.info(_block.info.parentHash()); _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -411,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif BlockInfo biGrandParent; - if (biParent.number) - biGrandParent = _bc.info(biParent.parentHash); + if (biParent.number()) + biGrandParent = _bc.info(biParent.parentHash()); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo()); + sync(_bc, _block.info.parentHash(), BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -462,17 +462,15 @@ void State::resetCurrent() m_cache.clear(); m_touched.clear(); m_currentBlock = BlockInfo(); - m_currentBlock.coinbaseAddress = m_ourAddress; - m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); - m_currentBlock.transactionsRoot = h256(); - m_currentBlock.sha3Uncles = h256(); + m_currentBlock.setCoinbaseAddress(m_ourAddress); + m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0))); m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); m_committedToMine = false; @@ -538,7 +536,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu catch (BlockGasLimitReached const& e) { bigint const& got = *boost::get_error_info(e); - if (got > m_currentBlock.gasLimit) + if (got > m_currentBlock.gasLimit()) { clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; _tq.drop(t.sha3()); @@ -583,7 +581,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number()); string ret; unsigned i = 0; @@ -604,12 +602,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == _block.info.parentHash); - assert(m_currentBlock.parentHash == _block.info.parentHash); - assert(rootHash() == m_previousBlock.stateRoot); + assert(m_previousBlock.hash() == _block.info.parentHash()); + assert(m_currentBlock.parentHash() == _block.info.parentHash()); + assert(rootHash() == m_previousBlock.stateRoot()); #endif - if (m_currentBlock.parentHash != m_previousBlock.hash()) + if (m_currentBlock.parentHash() != m_previousBlock.hash()) // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); @@ -622,7 +620,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) LastHashes lh; DEV_TIMED_ABOVE("lastHashes", 500) - lh = _bc.lastHashes((unsigned)m_previousBlock.number); + lh = _bc.lastHashes((unsigned)m_previousBlock.number()); RLP rlp(_block.block); @@ -651,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) } h256 receiptsRoot; - DEV_TIMED_ABOVE("receiptsRoot", 500) + DEV_TIMED_ABOVE(".receiptsRoot()", 500) receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) + if (receiptsRoot != m_currentBlock.receiptsRoot()) { InvalidReceiptsStateRoot ex; - ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot()); ex << errinfo_receipts(receipts); ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } - if (m_currentBlock.logBloom != logBloom()) + if (m_currentBlock.logBloom() != logBloom()) { InvalidLogBloom ex; - ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom()); ex << errinfo_receipts(receipts); BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. - u256 tdIncrease = m_currentBlock.difficulty; + u256 tdIncrease = m_currentBlock.difficulty(); // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) @@ -686,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) vector rewarded; h256Hash excluded; DEV_TIMED_ABOVE("allKin", 500) - excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; @@ -710,22 +708,22 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) + if (!_bc.isKnown(uncle.parentHash())) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + uncleParent = BlockInfo(_bc.block(uncle.parentHash())); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7) { UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } - else if (uncle.number == m_currentBlock.number) + else if (uncle.number() == m_currentBlock.number()) { UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } uncle.verifyParent(uncleParent); @@ -748,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash()) { m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot())); } - if (m_currentBlock.gasUsed != gasUsed()) + if (m_currentBlock.gasUsed() != gasUsed()) { // Rollback the trie. m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed()))); } return tdIncrease; @@ -772,7 +770,7 @@ void State::cleanup(bool _fullCommit) // Commit the new trie to disk. if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -786,7 +784,7 @@ void State::cleanup(bool _fullCommit) m_db.commit(); if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -806,7 +804,7 @@ void State::uncommitToMine() { m_cache.clear(); if (!m_transactions.size()) - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); else m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; @@ -878,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock.number != 0) + if (m_previousBlock.number() != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); - auto p = m_previousBlock.parentHash; +// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl; + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; @@ -926,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = hash256(transactionsMap); - m_currentBlock.receiptsRoot = hash256(receiptsMap); - m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); - // Apply rewards last of all. applyRewards(uncleBlockHeaders); @@ -941,12 +934,18 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // cnote << m_state; // cnote << *this; - m_currentBlock.gasUsed = gasUsed(); - m_currentBlock.stateRoot = m_state.root(); - m_currentBlock.parentHash = m_previousBlock.hash(); - m_currentBlock.extraData = _extraData; - if (m_currentBlock.extraData.size() > 32) - m_currentBlock.extraData.resize(32); + m_currentBlock.setLogBloom(logBloom()); + m_currentBlock.setGasUsed(gasUsed()); + m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root()); + + m_currentBlock.setParentHash(m_previousBlock.hash()); + m_currentBlock.setExtraData(_extraData); + if (m_currentBlock.extraData().size() > 32) + { + auto ed = m_currentBlock.extraData(); + ed.resize(32); + m_currentBlock.setExtraData(ed); + } m_committedToMine = true; } @@ -967,13 +966,13 @@ bool State::sealBlock(bytesConstRef _header) ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); - cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; + cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")"; // TODO: move into Sealer StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), "", // Can't give the nonce here. "", //TODO: chain head hash here ?? - m_currentBlock.parentHash.abridged() + m_currentBlock.parentHash().abridged() ); // Quickly reset the transactions. @@ -1270,7 +1269,7 @@ State State::fromPending(unsigned _i) const ret.m_cache.clear(); _i = min(_i, m_transactions.size()); if (!_i) - ret.m_state.setRoot(m_previousBlock.stateRoot); + ret.m_state.setRoot(m_previousBlock.stateRoot()); else ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) @@ -1287,10 +1286,10 @@ void State::applyRewards(vector const& _uncleBlockHeaders) u256 r = m_blockReward; for (auto const& i: _uncleBlockHeaders) { - addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8); + addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8); r += m_blockReward / 32; } - addBalance(m_currentBlock.coinbaseAddress, r); + addBalance(m_currentBlock.coinbaseAddress(), r); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) diff --git a/libethereum/State.h b/libethereum/State.h index 805215ee5..e2bda6f24 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } + u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); } /// Check if the address is in use. bool addressInUse(Address _address) const; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..a5c45af26 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -83,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry ): LogEntry(_le), blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), + blockNumber((BlockNumber)_bi.number()), transactionHash(_th), transactionIndex(_ti), logIndex(_li), @@ -205,7 +205,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } + h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2b2ada0ae..f95481c54 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress()); break; case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); + m_stack.push_back(_ext.currentBlock.timestamp()); break; case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); + m_stack.push_back(_ext.currentBlock.number()); break; case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); + m_stack.push_back(_ext.currentBlock.difficulty()); break; case Instruction::GASLIMIT: - m_stack.push_back(_ext.currentBlock.gasLimit); + m_stack.push_back(_ext.currentBlock.gasLimit()); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libtestutils/BlockChainLoader.cpp b/libtestutils/BlockChainLoader.cpp index e6c47e2fe..7e08243af 100644 --- a/libtestutils/BlockChainLoader.cpp +++ b/libtestutils/BlockChainLoader.cpp @@ -36,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) // load genesisBlock m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); - assert(m_state.rootHash() == m_bc->info().stateRoot); + assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks for (auto const& block: _json["blocks"]) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 15d39bded..fae12708c 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -88,18 +88,18 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) if (_bi) { res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["parentHash"] = toJS(_bi.parentHash()); + res["sha3Uncles"] = toJS(_bi.sha3Uncles()); + res["miner"] = toJS(_bi.coinbaseAddress()); + res["stateRoot"] = toJS(_bi.stateRoot()); + res["transactionsRoot"] = toJS(_bi.transactionsRoot()); res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); + res["number"] = toJS(_bi.number()); res["gasUsed"] = toJS(_bi.gasUsed); res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["logsBloom"] = toJS(_bi.logBloom); + res["timestamp"] = toJS(_bi.timestamp()); + res["extraData"] = toJS(_bi.extraData()); + res["logsBloom"] = toJS(_bi.logBloom()); res["target"] = toJS(_bi.boundary()); // TODO: move into ProofOfWork. @@ -140,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number())); } return res; } @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()); + res["stateRoot"] = toJS(_t.stateRoot()()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b43c4db51..bae980a7e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -151,12 +151,12 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); m_environment.currentBlock.number = toInt(_o["currentNumber"]); m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 9ee93779e..7dbc5c91e 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(blocks) u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString()); h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString())); h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); - ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom); - ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress); + ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); + ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), - _blockInfo.extraData.begin(), - _blockInfo.extraData.end() + _blockInfo.extraData().begin(), + _blockInfo.extraData().end() ); ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); @@ -132,11 +132,11 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); - ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp); - ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles); + ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); + ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; BlockInfo blockInfo = _client.blockInfo(blockHash); diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 20f60618f..cf44dfd9f 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -66,7 +66,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,9 +76,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot = trueState.rootHash(); + biGenesisBlock.stateRoot() = trueState.rootHash(); else - TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -125,7 +125,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TransientDirectory td_stateDB, td_bc; BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -225,7 +225,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); updatePoW(current_BlockHeader); } @@ -302,7 +302,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (o.count("expect") > 0) { stateOptionsMap expectStateMap; - State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); @@ -313,7 +313,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section - State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); }//_fillin @@ -374,19 +374,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); @@ -551,7 +551,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp = (u256)time(0); + uncleBlockFromFields.timestamp() = (u256)time(0); cnote << "uncle block n = " << toString(uncleBlockFromFields.number); if (_vBiBlocks.size() > 2) { @@ -568,15 +568,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash; - uncleBlockFromFields.stateRoot = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot; + uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); + uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); if (overwrite == "timestamp") { - uncleBlockFromFields.timestamp = toInt(uncleHeaderObj["timestamp"]); + uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); } } @@ -660,19 +660,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { BlockInfo tmp = _header; if (ho.count("parentHash")) - tmp.parentHash = h256(ho["parentHash"].get_str()); + tmp.parentHash() = h256(ho["parentHash"].get_str()); if (ho.count("uncleHash")) - tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); if (ho.count("coinbase")) - tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); if (ho.count("stateRoot")) - tmp.stateRoot = h256(ho["stateRoot"].get_str()); + tmp.stateRoot() = h256(ho["stateRoot"].get_str()); if (ho.count("transactionsTrie")) - tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); if (ho.count("receiptTrie")) - tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); if (ho.count("bloom")) - tmp.logBloom = LogBloom(ho["bloom"].get_str()); + tmp.logBloom() = LogBloom(ho["bloom"].get_str()); if (ho.count("difficulty")) tmp.difficulty = toInt(ho["difficulty"]); if (ho.count("number")) @@ -682,9 +682,9 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) if (ho.count("gasUsed")) tmp.gasUsed = toInt(ho["gasUsed"]); if (ho.count("timestamp")) - tmp.timestamp = toInt(ho["timestamp"]); + tmp.timestamp() = toInt(ho["timestamp"]); if (ho.count("extraData")) - tmp.extraData = importByteArray(ho["extraData"].get_str()); + tmp.extraData() = importByteArray(ho["extraData"].get_str()); // find new valid nonce if (tmp != _header && tmp.difficulty) @@ -751,19 +751,19 @@ mArray writeTransactionsToJson(Transactions const& txs) mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) { - _o["parentHash"] = toString(_bi.parentHash); - _o["uncleHash"] = toString(_bi.sha3Uncles); - _o["coinbase"] = toString(_bi.coinbaseAddress); - _o["stateRoot"] = toString(_bi.stateRoot); - _o["transactionsTrie"] = toString(_bi.transactionsRoot); - _o["receiptTrie"] = toString(_bi.receiptsRoot); - _o["bloom"] = toString(_bi.logBloom); + _o["parentHash"] = toString(_bi.parentHash()); + _o["uncleHash"] = toString(_bi.sha3Uncles()); + _o["coinbase"] = toString(_bi.coinbaseAddress()); + _o["stateRoot"] = toString(_bi.stateRoot()); + _o["transactionsTrie"] = toString(_bi.transactionsRoot()); + _o["receiptTrie"] = toString(_bi.receiptsRoot()); + _o["bloom"] = toString(_bi.logBloom()); _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); - _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); + _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); _o["hash"] = toString(_bi.hash()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 02ff4517a..2d5a2faa6 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index fdfb180fb..28b2e43ab 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -83,10 +83,10 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st mObject FakeExtVM::exportEnv() { mObject ret; - ret["previousHash"] = toString(currentBlock.parentHash); + ret["previousHash"] = toString(currentBlock.parentHash()); ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); - ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp, HexPrefix::Add, 1); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); return ret; @@ -102,13 +102,13 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash = h256(_o["previousHash"].get_str()); + currentBlock.parentHash() = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } mObject FakeExtVM::exportState() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d44545145..4a6507cd6 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1188,7 +1188,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " return block.timestamp() == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/third/MainWin.cpp b/third/MainWin.cpp index f2a90cc0b..a3b05572f 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From 0adfc1ea842f28e92b93d85d43c60bc30f4c43f8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:34:11 +0200 Subject: [PATCH 077/113] Minor fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ec37302a2..357926d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -98,7 +98,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + bc().rescue(m_stateDB); m_gp->update(bc()); From b3a1bfea4ca82de19d2d6c6f19f73b4034676933 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 11:43:23 +0200 Subject: [PATCH 078/113] fixed build --- evmjit/libevmjit-cpp/JitVM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 4e1fb66ea..d96da87c1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -42,10 +42,10 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); - m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); - m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); - m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); + m_data.difficulty = eth2jit(_ext.currentBlock.difficulty()); + m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit()); + m_data.number = static_cast(_ext.currentBlock.number()); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); From 388489b7d49351ef5e93367c682ee8cdaee04c37 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 16:45:23 +0200 Subject: [PATCH 079/113] mix working --- CMakeLists.txt | 28 +++++++------- alethzero/MainWin.cpp | 53 ++++++++++++++------------- alethzero/MiningView.cpp | 4 +- alethzero/MiningView.h | 4 +- exp/CMakeLists.txt | 4 +- libethereum/BlockChain.cpp | 1 - libtestutils/BlockChainLoader.cpp | 3 +- libtestutils/StateLoader.cpp | 2 +- libtestutils/StateLoader.h | 2 + libweb3jsonrpc/JsonHelper.cpp | 8 ++-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libwebthree/WebThree.cpp | 2 +- mix/ClientModel.cpp | 4 +- mix/MixClient.cpp | 36 +++++++++--------- mix/MixClient.h | 36 +++++++++++++++--- 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b410d875c..89d3c167a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,13 +403,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) -# add_subdirectory(libweb3jsonrpc) + add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) -# add_subdirectory(libjsengine) -# add_subdirectory(libjsconsole) -# add_subdirectory(ethconsole) + add_subdirectory(libjsengine) + add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -437,31 +437,31 @@ add_subdirectory(libethcore) if (GENERAL) add_subdirectory(libevm) add_subdirectory(libethereum) -# add_subdirectory(libwebthree) + add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) -# add_subdirectory(ethminer) + add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) -# add_subdirectory(ethkey) + add_subdirectory(ethkey) endif () if (TESTS) -# add_subdirectory(libtestutils) -# add_subdirectory(test) + add_subdirectory(libtestutils) + add_subdirectory(test) if (JSONRPC) -# add_subdirectory(ethrpctest) + add_subdirectory(ethrpctest) endif () endif () if (TOOLS) -# add_subdirectory(rlp) -# add_subdirectory(abi) -# add_subdirectory(ethvm) -# add_subdirectory(eth) + add_subdirectory(rlp) + add_subdirectory(abi) + add_subdirectory(ethvm) + add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ad8f5528c..181772ddb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,9 +189,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; - auto block = CanonBlockChain::createGenesisBlock(); - cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl; @@ -208,13 +208,14 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); @@ -1124,7 +1125,7 @@ void Main::refreshMining() QString t; if (gp.first != EthashAux::NotGenerating) t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second); - MiningProgress p = ethereum()->miningProgress(); + WorkingProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining")); if (ethereum()->isMining() && p.hashes > 0) { @@ -1629,7 +1630,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1699,7 +1700,7 @@ void Main::on_blocks_currentItemChanged() auto details = ethereum()->blockChain().details(h); auto blockData = ethereum()->blockChain().block(h); auto block = RLP(blockData); - BlockInfo info(blockData); + Ethash::BlockHeader info(blockData); stringstream s; @@ -1709,21 +1710,21 @@ void Main::on_blocks_currentItemChanged() time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; - s << "

#" << info.number; + s << "

#" << info.number(); s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
"; s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; - s << "
Mix hash: " << info.mixHash << "" << "
"; - s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; - s << "
Difficulty: " << info.difficulty << "" << "
"; - if (info.number) + s << "
Mix hash: " << info.mixHash() << "" << "
"; + s << "
Nonce: " << info.nonce() << "" << "
"; + s << "
Hash w/o nonce: " << info.hashWithout() << "" << "
"; + s << "
Difficulty: " << info.difficulty() << "" << "
"; + if (info.number()) { - auto e = EthashAux::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce()); + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash() << "" << "
"; } else @@ -1740,19 +1741,19 @@ void Main::on_blocks_currentItemChanged() s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { - BlockInfo uncle = BlockInfo::fromHeader(u.data()); + Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; s << line << "Parent: " << uncle.parentHash() << "" << ""; - s << line << "Number: " << uncle.number << "" << ""; + s << line << "Number: " << uncle.number() << "" << ""; s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; - s << line << "Mix hash: " << uncle.mixHash << "" << ""; - s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Mix hash: " << uncle.mixHash() << "" << ""; + s << line << "Nonce: " << uncle.nonce() << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; - s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = EthashAux::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; + s << line << "Difficulty: " << uncle.difficulty() << "" << ""; + auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce()); + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash()) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; @@ -1764,7 +1765,7 @@ void Main::on_blocks_currentItemChanged() unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } s << "
Post: " << info.stateRoot() << "" << "
"; @@ -1807,7 +1808,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index e020408ea..fb9de0346 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MiningProgress; +using dev::eth::WorkingProgress; // functions using dev::toString; @@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MiningProgress const& _p) +void MiningView::appendStats(list const& _i, WorkingProgress const& _p) { (void)_p; if (_i.empty()) diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 65b9f2ec9..ae81a7cc4 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); + void appendStats(std::list const& _l, dev::eth::WorkingProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MiningProgress m_progress; + dev::eth::WorkingProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 5f876a69b..a9bc09db7 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,10 +18,10 @@ if (READLINE_FOUND) endif() if (JSONRPC) -# target_link_libraries(${EXECUTABLE} web3jsonrpc) + target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -#target_link_libraries(${EXECUTABLE} webthree) +target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b696c77bd..03ab1b46a 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -137,7 +137,6 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map #include "BlockChainLoader.h" #include "StateLoader.h" #include "Common.h" @@ -35,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) m_state = sl.state(); // load genesisBlock - m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); + m_bc.reset(new FullBlockChain(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill)); assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks diff --git a/libtestutils/StateLoader.cpp b/libtestutils/StateLoader.cpp index 235f1c573..cd5c37e96 100644 --- a/libtestutils/StateLoader.cpp +++ b/libtestutils/StateLoader.cpp @@ -27,7 +27,7 @@ using namespace dev::eth; using namespace dev::test; StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): - m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty) + m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty) { for (string const& name: _json.getMemberNames()) { diff --git a/libtestutils/StateLoader.h b/libtestutils/StateLoader.h index 47eb26900..c66f53148 100644 --- a/libtestutils/StateLoader.h +++ b/libtestutils/StateLoader.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace dev { @@ -38,6 +39,7 @@ class StateLoader public: StateLoader(Json::Value const& _json, std::string const& _dbPath); eth::State const& state() const { return m_state; } + eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; } private: eth::State m_state; diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index fae12708c..54fde52e8 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -93,10 +93,10 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["miner"] = toJS(_bi.coinbaseAddress()); res["stateRoot"] = toJS(_bi.stateRoot()); res["transactionsRoot"] = toJS(_bi.transactionsRoot()); - res["difficulty"] = toJS(_bi.difficulty); + res["difficulty"] = toJS(_bi.difficulty()); res["number"] = toJS(_bi.number()); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); + res["gasUsed"] = toJS(_bi.gasUsed()); + res["gasLimit"] = toJS(_bi.gasLimit()); res["timestamp"] = toJS(_bi.timestamp()); res["extraData"] = toJS(_bi.extraData()); res["logsBloom"] = toJS(_bi.logBloom()); @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()()); + res["stateRoot"] = toJS(_t.stateRoot()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 3aff9cf23..bf49d3322 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str return true; } -dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +dev::eth::BlockChain const& WebThreeStubServer::bc() const { return m_web3.ethereum()->blockChain(); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4d545c90e..2860f852b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -34,7 +34,7 @@ namespace eth { class KeyManager; class TrivialGasPricer; -class CanonBlockChain; +class BlockChain; class BlockQueue; } @@ -89,7 +89,7 @@ private: private: h256 blockHash(std::string const& _blockNumberOrHash) const; - dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockChain const& bc() const; dev::eth::BlockQueue const& bq() const; dev::WebThreeDirect& m_web3; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 3c1dea40f..7889b5935 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect( Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) { - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); + m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr(), _dbPath, _we, 0)); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 90ff19feb..5c5f2f4cd 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); stringstream strGas; - strGas << blockInfo.gasUsed; + strGas << blockInfo.gasUsed(); stringstream strNumber; - strNumber << blockInfo.number; + strNumber << blockInfo.number(); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ea4686601..eef6ad6ec 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -24,12 +24,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include "Exceptions.h" using namespace std; @@ -45,22 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho namespace { +} -struct MixPow //dummy POW +MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot): + FullBlockChain(createGenesisBlock(_stateRoot), std::unordered_map(), _path, WithExisting::Kill) { - typedef int Solution; - static bool verify(BlockInfo const&) { return true; } -}; - } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(15) + block.appendList(13) << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); + << std::string(); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -78,7 +77,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,12 +89,13 @@ void MixClient::resetState(std::unordered_map const& _accounts SecureTrieDB accountState(&m_stateDB); accountState.init(); - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + dev::eth::commit(_accounts, accountState); h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); + State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + s.sync(bc()); + m_state = s; m_startState = m_state; WriteGuard lx(x_executions); m_executions.clear(); @@ -275,11 +274,14 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + + NoProof::BlockHeader h(m_state.info()); + RLPStream header; + h.streamRLP(header); + m_state.sealBlock(header.out()); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; } ExecutionResult MixClient::lastExecution() const @@ -383,9 +385,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MiningProgress MixClient::miningProgress() const +eth::WorkingProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::WorkingProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..279692de5 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,13 +33,40 @@ namespace dev { + namespace mix { -class MixBlockChain: public dev::eth::BlockChain +class NoProof +{ + class BlockHeaderRaw: public dev::eth::BlockInfo + { + public: + static const unsigned SealFields = 0; + + protected: + BlockHeaderRaw() = default; + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; } + void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; } + void streamRLPFields(RLPStream& _s) const { (void) _s; } + }; + +public: + + static std::string name() { return "NoProof"; } + static unsigned revision() { return 0; } + using BlockHeader = dev::eth::BlockHeaderPolished; + +private: + static AddressHash s_authorities; +}; + +class MixBlockChain: public dev::eth::FullBlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {} + MixBlockChain(std::string const& _path, h256 _stateRoot); static bytes createGenesisBlock(h256 _stateRoot); }; @@ -67,9 +95,7 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MiningProgress miningProgress() const override; - eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } - bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } + eth::WorkingProgress miningProgress() const override; virtual void flushTransactions() override {} /// @returns the last mined block information From 67bb58d6e41ab9227e73abef6c8189c01349fff0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 18:11:08 +0200 Subject: [PATCH 080/113] started tests refactoring --- libethcore/Common.h | 3 ++- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 9 +++++---- libethereum/BlockQueue.cpp | 2 +- libethereum/Client.cpp | 3 +-- mix/MixClient.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libethcore/dagger.cpp | 4 ++-- test/libethereum/ClientBase.cpp | 14 +++++++------- test/libethereum/genesis.cpp | 6 +++--- test/libethereum/stateOriginal.cpp | 5 +++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 5c0a0cc79..116e1d5ed 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -130,9 +130,10 @@ struct ImportRequirements TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, None = 0 }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 03ab1b46a..8a654fa51 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 3ff85c8a6..811da8609 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -118,12 +118,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -391,7 +391,8 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash())); + if ((_ir & ImportRequirements::Parent) != 0) + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c9ee4c1cf..d0ca34b1c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); } catch (...) { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 357926d03..d43f240b7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -84,10 +84,9 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database // until after the construction. m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); - m_preMine = State(m_stateDB); - m_postMine = State(m_stateDB); // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. m_preMine = bc().genesisState(m_stateDB); + m_postMine = m_preMine; m_bq.setChain(bc()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index eef6ad6ec..67f2a2507 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -279,7 +279,7 @@ void MixClient::mine() RLPStream header; h.streamRLP(header); m_state.sealBlock(header.out()); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bae980a7e..30f323369 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,7 +63,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 061b5ae79..8d4cba933 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); - BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); + BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); BOOST_REQUIRE_EQUAL(nonce, header.nonce); unsigned cacheSize(o["cache_size"].get_int()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 7dbc5c91e..a426ff53f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -119,21 +119,21 @@ BOOST_AUTO_TEST_CASE(blocks) h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); - ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); + ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty()); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), _blockInfo.extraData().begin(), _blockInfo.extraData().end() ); - ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); - ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); + ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit()); + ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed()); ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash()); - ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); - ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); - ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); + ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash()); + ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce()); + ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number()); ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 2d5a2faa6..39997572f 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,9 +60,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e3f8ac29f..163c89e50 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ BOOST_AUTO_TEST_CASE(Complex) Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; + OverlayDB stateDB = State::openDB(h256()); + CanonBlockChain bc; cout << bc; State s = bc.genesisState(stateDB); From 1547a72b3a73b32115c70c3673ce6b710af1f090 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 20:53:58 +0200 Subject: [PATCH 081/113] eth working --- eth/main.cpp | 2 +- ethminer/MinerAux.h | 26 ++++++++++++-------------- libethcore/BlockInfo.h | 1 + libethereum/Client.h | 6 +++++- test/TestHelper.cpp | 17 ++++++++++++----- test/libethcore/dagger.cpp | 6 +++--- test/libethereum/ClientBase.cpp | 4 ++-- test/libethereum/gaspricer.cpp | 3 ++- test/libevm/vm.cpp | 10 +++++----- 9 files changed, 43 insertions(+), 32 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 7ce4d49c2..0b83c97b4 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1310,7 +1310,7 @@ int main(int argc, char** argv) { try { - CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); } catch (...) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 0d227b1ef..01083012f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -397,17 +397,16 @@ public: private: void doInitDAG(unsigned _n) { - BlockInfo bi; - bi.number() = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; - Ethash::prep(bi); + h256 seedHash = EthashAux::seedHash(_n); + cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl; + EthashAux::full(seedHash, true); exit(0); } void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) { - BlockInfo genesis; - genesis.difficulty = 1 << 18; + Ethash::BlockHeader genesis; + genesis.setDifficulty(1 << 18); cdebug << genesis.boundary(); GenericFarm f; @@ -417,17 +416,16 @@ private: cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; - Ethash::prep(genesis); + genesis.prep(); - genesis.difficulty = u256(1) << 63; - genesis.noteDirty(); + genesis.setDifficulty(u256(1) << 63); f.setWork(genesis); if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); - map results; + map results; uint64_t mean = 0; uint64_t innerMean = 0; for (unsigned i = 0; i <= _trials; ++i) @@ -488,9 +486,9 @@ private: Farm rpc(client); GenericFarm f; if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 67a5397f4..c310b3dd9 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -128,6 +128,7 @@ public: void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } Address const& coinbaseAddress() const { return m_coinbaseAddress; } h256 const& stateRoot() const { return m_stateRoot; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 73609bd71..4523d324b 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -77,7 +77,7 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); * @brief Main API hub for interfacing with Ethereum. * Not to be used directly - subclass. */ -class Client: public ClientBase, Worker +class Client: public ClientBase, protected Worker { public: /// New-style Constructor. @@ -342,6 +342,8 @@ public: init(_host, _dbPath, _forceAction, _networkId); } + virtual ~SpecialisedClient() { stopWorking(); } + /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } @@ -365,6 +367,8 @@ public: u256 _networkId = 0 ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + virtual ~EthashClient() { stopWorking(); } + /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. virtual std::tuple getEthashWork() override; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 30f323369..c29788b9f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -63,11 +64,17 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + Ethash::BlockHeader header(s.info); + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { - return completed = s.completeMine(sol); + header.m_mixHash = sol.mixHash; + header.m_nonce = sol.nonce; + RLPStream ret; + header.streamRLP(ret); + s.sealBlock(ret); + return true; }); f.setWork(s.info()); f.startCPU(); @@ -77,9 +84,9 @@ void mine(State& s, BlockChain const& _bc) void mine(BlockInfo& _bi) { - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { _bi.proof = sol; return completed = true; diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 8d4cba933..c3cd75b0d 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(basic_test) h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); - BOOST_REQUIRE_EQUAL(nonce, header.nonce); + BOOST_REQUIRE_EQUAL(nonce, header.nonce()); unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - EthashProofOfWork::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header.seedHash(), header.hashWithout(), header.nonce()); BOOST_REQUIRE_EQUAL(r.value, result); - BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); + BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash()); } } diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index a426ff53f..f9d83e9c6 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber); // blockInfo - auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void + auto compareBlockInfos = [](Json::Value const& _b, Ethash::BlockHeader _blockInfo) -> void { LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString())); Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString())); @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - BlockInfo blockInfo = _client.blockInfo(blockHash); + Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index ce49a4a20..050ab2d25 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer) std::shared_ptr gp(new TrivialGasPricer); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); - gp->update(BlockChain(bytes(), TransientDirectory().path(), WithExisting::Kill)); + gp->update(FullBlockChain(bytes(), StateDefinition(), TransientDirectory().path(), WithExisting::Kill)); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 28b2e43ab..badabd70c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number()), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -84,11 +84,11 @@ mObject FakeExtVM::exportEnv() { mObject ret; ret["previousHash"] = toString(currentBlock.parentHash()); - ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); + ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1); ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); - ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); - ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); + ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1); + ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1); return ret; } @@ -107,7 +107,7 @@ void FakeExtVM::importEnv(mObject& _o) lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } From 3202427722e5b2e70a1bbd2aa545ccabe7044cfb Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 18 Jul 2015 15:19:15 +0200 Subject: [PATCH 082/113] tests repared --- libethcore/BlockInfo.h | 2 +- libethereum/BlockChain.h | 7 +- test/TestHelper.cpp | 109 +++++++---- test/TestHelper.h | 19 +- test/fuzzTesting/checkRandomStateTest.cpp | 2 +- test/fuzzTesting/createRandomStateTest.cpp | 2 +- test/libethcore/dagger.cpp | 2 +- test/libethereum/ClientBase.cpp | 3 +- test/libethereum/blockchain.cpp | 203 ++++++++++----------- test/libethereum/genesis.cpp | 2 +- test/libethereum/state.cpp | 2 +- test/libevm/vm.cpp | 27 ++- 12 files changed, 221 insertions(+), 159 deletions(-) diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index c310b3dd9..8d5264361 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -209,7 +209,7 @@ public: void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); - BlockInfo::parentHash = _parent.hash(); + BlockInfo::m_parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); BlockInfoSub::populateFromParent(_parent); } diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 811da8609..7b89d3f99 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -392,7 +392,12 @@ public: BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); if ((_ir & ImportRequirements::Parent) != 0) - h.verifyParent(header(h.parentHash())); + { + bytes parentHeader(headerData(h.parentHash())); + if (parentHeader.empty()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + h.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, h.parentHash(), HeaderData)); + } res.info = static_cast(h); } catch (Exception& ex) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index c29788b9f..aec72285c 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,38 +63,23 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { + std::unique_ptr sealer(Ethash::createSealEngine()); s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - Ethash::BlockHeader header(s.info); - f.onSolutionFound([&](EthashProofOfWork::Solution sol) - { - header.m_mixHash = sol.mixHash; - header.m_nonce = sol.nonce; - RLPStream ret; - header.streamRLP(ret); - s.sealBlock(ret); - return true; - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); -} - -void mine(BlockInfo& _bi) -{ - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](EthashProofOfWork::Solution sol) - { - _bi.proof = sol; - return completed = true; - }); - f.setWork(_bi); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + sealer->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + sealer->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); +} + +void mine(Ethash::BlockHeader& _bi) +{ + std::unique_ptr sealer(Ethash::createSealEngine()); + Notified sealed; + sealer->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + sealer->generateSeal(_bi); + sealed.waitNot({}); + _bi = Ethash::BlockHeader(sealed); } } @@ -158,13 +143,24 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); - m_environment.currentBlock.number = toInt(_o["currentNumber"]); - m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); - m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); - + RLPStream rlpStream; + rlpStream.appendList(BlockInfo::BasicFields); + + rlpStream << h256(_o["previousHash"].get_str()); + rlpStream << EmptyListSHA3; + rlpStream << Address(_o["currentCoinbase"].get_str()); + rlpStream << h256(); // stateRoot + rlpStream << EmptyTrie; // transactionTrie + rlpStream << EmptyTrie; // receiptTrie + rlpStream << LogBloom(); // bloom + rlpStream << toInt(_o["currentDifficulty"]); + rlpStream << toInt(_o["currentNumber"]); + rlpStream << toInt(_o["currentGasLimit"]); + rlpStream << 0; //gasUsed + rlpStream << toInt(_o["currentTimestamp"]); + rlpStream << std::string(); //extra data + + m_environment.currentBlock = BlockInfo(rlpStream.out(), CheckEverything, h256{}, HeaderData); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; } @@ -824,6 +820,43 @@ LastHashes lastHashes(u256 _currentBlockNumber) return ret; } +dev::eth::Ethash::BlockHeader constructHeader( + h256 const& _parentHash, + h256 const& _sha3Uncles, + Address const& _coinbaseAddress, + h256 const& _stateRoot, + h256 const& _transactionsRoot, + h256 const& _receiptsRoot, + dev::eth::LogBloom const& _logBloom, + u256 const& _difficulty, + u256 const& _number, + u256 const& _gasLimit, + u256 const& _gasUsed, + u256 const& _timestamp, + bytes const& _extraData) +{ + RLPStream rlpStream; + rlpStream.appendList(Ethash::BlockHeader::Fields); + + rlpStream << _parentHash << _sha3Uncles << _coinbaseAddress << _stateRoot << _transactionsRoot << _receiptsRoot << _logBloom + << _difficulty << _number << _gasLimit << _gasUsed << _timestamp << _extraData << h256{} << Nonce{}; + + return Ethash::BlockHeader(rlpStream.out()); +} + +void updateEthashSeal(dev::eth::Ethash::BlockHeader& _header, h256 const& _mixHash, dev::eth::Nonce const& _nonce) +{ + RLPStream source; + _header.streamRLP(source); + RLP sourceRlp(source.out()); + RLPStream header; + header.appendList(Ethash::BlockHeader::Fields); + for (size_t i = 0; i < BlockInfo::BasicFields; i++) + header << sourceRlp[i]; + + header << _mixHash << _nonce; + _header = Ethash::BlockHeader(header.out()); +} namespace { diff --git a/test/TestHelper.h b/test/TestHelper.h index 420278838..48eb42c55 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -27,6 +27,7 @@ #include #include "JsonSpiritHeaders.h" +#include #include #include #include @@ -62,7 +63,7 @@ class State; void mine(Client& c, int numBlocks); void connectClients(Client& c1, Client& c2); void mine(State& _s, BlockChain const& _bc); -void mine(BlockInfo& _bi); +void mine(Ethash::BlockHeader& _bi); } @@ -175,7 +176,21 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o); void checkStorage(std::map _expectedStore, std::map _resultStore, Address _expectedAddr); void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs); void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates); - +dev::eth::Ethash::BlockHeader constructHeader( + h256 const& _parentHash, + h256 const& _sha3Uncles, + Address const& _coinbaseAddress, + h256 const& _stateRoot, + h256 const& _transactionsRoot, + h256 const& _receiptsRoot, + dev::eth::LogBloom const& _logBloom, + u256 const& _difficulty, + u256 const& _number, + u256 const& _gasLimit, + u256 const& _gasUsed, + u256 const& _timestamp, + bytes const& _extraData); +void updateEthashSeal(dev::eth::Ethash::BlockHeader& _header, h256 const& _mixHash, dev::eth::Nonce const& _nonce); void executeTests(const std::string& _name, const std::string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function doTests); void userDefinedTest(std::function doTests); RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj); diff --git a/test/fuzzTesting/checkRandomStateTest.cpp b/test/fuzzTesting/checkRandomStateTest.cpp index 01366cd4d..adbb953f3 100644 --- a/test/fuzzTesting/checkRandomStateTest.cpp +++ b/test/fuzzTesting/checkRandomStateTest.cpp @@ -87,7 +87,7 @@ bool doStateTest(mValue& _v) try { - output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index d533ac2da..be751f2b7 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -233,7 +233,7 @@ void doStateTests(json_spirit::mValue& _v) eth::State theState = importer.m_statePre; try { - output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index c3cd75b0d..0e69793e2 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing, h256{}, HeaderData); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index f9d83e9c6..7c9b7197f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -21,6 +21,7 @@ #include #include +#include #include "../TestUtils.h" using namespace std; @@ -139,7 +140,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); + Ethash::BlockHeader blockInfo((static_cast(_client)).bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index cf44dfd9f..6d4761bb9 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -37,16 +37,17 @@ namespace dev { namespace test { typedef std::vector uncleList; typedef std::pair blockSet; -BlockInfo constructBlock(mObject& _o); -bytes createBlockRLPFromFields(mObject& _tObj); -RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList); +using BlockHeader = Ethash::BlockHeader; + +BlockHeader constructBlock(mObject& _o, h256 const& _stateRoot = h256{}); +bytes createBlockRLPFromFields(mObject& _tObj, h256 const& _stateRoot = h256{}); +RLPStream createFullBlockFromHeader(BlockHeader const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList); mArray writeTransactionsToJson(Transactions const& txs); -mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi); -void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj); -BlockInfo constructBlock(mObject& _o); -void updatePoW(BlockInfo& _bi); -mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); +mObject writeBlockHeaderToJson(mObject& _o, BlockHeader const& _bi); +void overwriteBlockHeader(BlockHeader& _current_BlockHeader, mObject& _blObj); +void updatePoW(BlockHeader& _bi); +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { @@ -61,12 +62,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) cerr << i.first << endl; TBOOST_REQUIRE(o.count("genesisBlockHeader")); - BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj()); TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); + BlockHeader biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj(), h256{}); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path(), h256{}, WithExisting::Kill)), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,7 +77,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot() = trueState.rootHash(); + biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj(), trueState.rootHash()); else TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); @@ -96,7 +97,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // construct true blockchain TransientDirectory td; - BlockChain trueBc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill); + FullBlockChain trueBc(rlpGenesisBlock.out(), StateDefinition(), td.path(), WithExisting::Kill); if (_fillin) { @@ -107,7 +108,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) genesis.first = rlpGenesisBlock.out(); genesis.second = uncleList(); blockSets.push_back(genesis); - vector vBiBlocks; + vector vBiBlocks; vBiBlocks.push_back(biGenesisBlock); size_t importBlockNumber = 0; @@ -124,8 +125,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) vBiBlocks.push_back(biGenesisBlock); TransientDirectory td_stateDB, td_bc; - BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); + FullBlockChain bc(rlpGenesisBlock.out(), StateDefinition(), td_bc.path(), WithExisting::Kill); + State state(OverlayDB(State::openDB(td_stateDB.path(), h256{}, WithExisting::Kill)), BaseState::Empty); + trueState.setAddress(biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -134,12 +136,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) BlockQueue uncleQueue; uncleList uncles = blockSets.at(i).second; for (size_t j = 0; j < uncles.size(); j++) - uncleQueue.import(&uncles.at(j), bc); + uncleQueue.import(&uncles.at(j), false); const bytes block = blockSets.at(i).first; bc.sync(uncleQueue, state.db(), 4); bc.attemptImport(block, state.db()); - vBiBlocks.push_back(BlockInfo(block)); + vBiBlocks.push_back(BlockHeader(block)); state.sync(bc); } @@ -156,7 +158,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } //get uncles - vector vBiUncles; + vector vBiUncles; blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks, blockSets); BlockQueue uncleBlockQueue; @@ -167,7 +169,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) RLPStream uncle = createFullBlockFromHeader(vBiUncles.at(i)); try { - uncleBlockQueue.import(&uncle.out(), bc); + uncleBlockQueue.import(&uncle.out(), false); uncleBlockQueueList.push_back(uncle.out()); // wait until block is verified this_thread::sleep_for(chrono::seconds(1)); @@ -205,14 +207,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) txList.push_back(txi); blObj["transactions"] = writeTransactionsToJson(txList); - BlockInfo current_BlockHeader = state.info(); + BlockHeader current_BlockHeader = state.info(); RLPStream uncleStream; uncleStream.appendList(vBiUncles.size()); for (unsigned i = 0; i < vBiUncles.size(); ++i) { RLPStream uncleRlp; - vBiUncles[i].streamRLP(uncleRlp, WithNonce); + vBiUncles[i].streamRLP(uncleRlp); uncleStream.appendRaw(uncleRlp.out()); } @@ -225,7 +227,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); + current_BlockHeader.setSha3Uncles(sha3(uncleStream.out())); updatePoW(current_BlockHeader); } @@ -330,7 +332,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blockRLP = importByteArray(blObj["rlp"].get_str()); trueState.sync(trueBc); trueBc.import(blockRLP, trueState.db()); - if (trueBc.info() != BlockInfo(blockRLP)) + if (trueBc.info() != BlockHeader(blockRLP)) importedAndBest = false; trueState.sync(trueBc); } @@ -363,17 +365,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(blObj.count("blockHeader")); mObject tObj = blObj["blockHeader"].get_obj(); - BlockInfo blockHeaderFromFields; + BlockHeader blockHeaderFromFields; const bytes c_rlpBytesBlockHeader = createBlockRLPFromFields(tObj); const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader); - blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce); + blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreSeal); - BlockInfo blockFromRlp = trueBc.info(); + BlockHeader blockFromRlp(trueBc.header()); if (importedAndBest) { //Check the fields restored from RLP to original fields - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithProof) == blockFromRlp.headerHash(WithProof)), "hash in given RLP not matching the block hash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); @@ -381,14 +383,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty() == blockFromRlp.difficulty()), "difficulty in given RLP not matching the block difficulty!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number() == blockFromRlp.number()), "number in given RLP not matching the block number!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit() == blockFromRlp.gasLimit()),"gasLimit in given RLP not matching the block gasLimit!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed() == blockFromRlp.gasUsed()), "gasUsed in given RLP not matching the block gasUsed!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash() == blockFromRlp.mixHash()), "mixHash in given RLP not matching the block mixHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce() == blockFromRlp.nonce()), "nonce in given RLP not matching the block nonce!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields == blockFromRlp), "However, blockHeaderFromFields != blockFromRlp!"); @@ -454,7 +456,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // check uncle list // uncles from uncle list field - vector uBlHsFromField; + vector uBlHsFromField; if (blObj["uncleHeaders"].type() != json_spirit::null_type) for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array()) { @@ -462,7 +464,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE((uBlH.size() == 16)); bytes uncleRLP = createBlockRLPFromFields(uBlH); const RLP c_uRLP(uncleRLP); - BlockInfo uncleBlockHeader; + BlockHeader uncleBlockHeader; try { uncleBlockHeader.populateFromHeader(c_uRLP); @@ -475,10 +477,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } // uncles from block RLP - vector uBlHsFromRlp; + vector uBlHsFromRlp; for (auto const& uRLP: root[2]) { - BlockInfo uBl; + BlockHeader uBl; uBl.populateFromHeader(uRLP); uBlHsFromRlp.push_back(uBl); } @@ -499,7 +501,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // helping functions -mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet) +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet) { // write uncle list mArray aUncleList; @@ -521,7 +523,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector { size_t number = (size_t)toInt(uncleHeaderObj["sameAsBlock"]); uncleHeaderObj.erase("sameAsBlock"); - BlockInfo currentUncle = _vBiBlocks[number]; + BlockHeader currentUncle = _vBiBlocks[number]; writeBlockHeaderToJson(uncleHeaderObj, currentUncle); aUncleList.push_back(uncleHeaderObj); _vBiUncles.push_back(currentUncle); @@ -532,7 +534,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector if (uncleHeaderObj.count("sameAsPreviousBlockUncle")) { bytes uncleRLP = _blockSet[(size_t)toInt(uncleHeaderObj["sameAsPreviousBlockUncle"])].second[0]; - BlockInfo uncleHeader(uncleRLP); + BlockHeader uncleHeader(uncleRLP); writeBlockHeaderToJson(uncleHeaderObj, uncleHeader); aUncleList.push_back(uncleHeaderObj); @@ -548,15 +550,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleHeaderObj.erase("overwriteAndRedoPoW"); } - BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); + BlockHeader uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp() = (u256)time(0); - cnote << "uncle block n = " << toString(uncleBlockFromFields.number); + uncleBlockFromFields.setTimestamp((u256)time(0)); + cnote << "uncle block n = " << toString(uncleBlockFromFields.number()); if (_vBiBlocks.size() > 2) { - if (uncleBlockFromFields.number - 1 < _vBiBlocks.size()) - uncleBlockFromFields.populateFromParent(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); + if (uncleBlockFromFields.number() - 1 < _vBiBlocks.size()) + uncleBlockFromFields.populateFromParent(_vBiBlocks[(size_t)uncleBlockFromFields.number() - 1]); else uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 2]); } @@ -565,29 +567,32 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector if (overwrite != "false") { - uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; - uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; - uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); - uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); + uncleBlockFromFields = constructHeader( + overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(), + uncleBlockFromFields.sha3Uncles(), + uncleBlockFromFields.coinbaseAddress(), + overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(), + uncleBlockFromFields.transactionsRoot(), + uncleBlockFromFields.receiptsRoot(), + uncleBlockFromFields.logBloom(), + overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : overwrite == "timestamp" ? uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number() - 1]) : uncleBlockFromFields.difficulty(), + uncleBlockFromFields.number(), + overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit(), + overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed(), + overwrite == "timestamp" ? toInt(uncleHeaderObj["timestamp"]) : uncleBlockFromFields.timestamp(), + uncleBlockFromFields.extraData()); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); - - if (overwrite == "timestamp") - { - uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); - uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); - } } updatePoW(uncleBlockFromFields); if (overwrite == "nonce") - uncleBlockFromFields.nonce = Nonce(uncleHeaderObj["nonce"].get_str()); + updateEthashSeal(uncleBlockFromFields, uncleBlockFromFields.mixHash(), Nonce(uncleHeaderObj["nonce"].get_str())); if (overwrite == "mixHash") - uncleBlockFromFields.mixHash = h256(uncleHeaderObj["mixHash"].get_str()); + updateEthashSeal(uncleBlockFromFields, h256(uncleHeaderObj["mixHash"].get_str()), uncleBlockFromFields.nonce()); writeBlockHeaderToJson(uncleHeaderObj, uncleBlockFromFields); @@ -600,7 +605,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector return aUncleList; } -bytes createBlockRLPFromFields(mObject& _tObj) +bytes createBlockRLPFromFields(mObject& _tObj, h256 const& _stateRoot) { RLPStream rlpStream; rlpStream.appendList(_tObj.count("hash") > 0 ? (_tObj.size() - 1) : _tObj.size()); @@ -614,7 +619,9 @@ bytes createBlockRLPFromFields(mObject& _tObj) if (_tObj.count("coinbase")) rlpStream << importByteArray(_tObj["coinbase"].get_str()); - if (_tObj.count("stateRoot")) + if (_stateRoot) + rlpStream << _stateRoot; + else if (_tObj.count("stateRoot")) rlpStream << importByteArray(_tObj["stateRoot"].get_str()); if (_tObj.count("transactionsTrie")) @@ -653,47 +660,35 @@ bytes createBlockRLPFromFields(mObject& _tObj) return rlpStream.out(); } -void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) +void overwriteBlockHeader(BlockHeader& _header, mObject& _blObj) { auto ho = _blObj["blockHeader"].get_obj(); if (ho.size() != 14) { - BlockInfo tmp = _header; - if (ho.count("parentHash")) - tmp.parentHash() = h256(ho["parentHash"].get_str()); - if (ho.count("uncleHash")) - tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); - if (ho.count("coinbase")) - tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); - if (ho.count("stateRoot")) - tmp.stateRoot() = h256(ho["stateRoot"].get_str()); - if (ho.count("transactionsTrie")) - tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); - if (ho.count("receiptTrie")) - tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); - if (ho.count("bloom")) - tmp.logBloom() = LogBloom(ho["bloom"].get_str()); - if (ho.count("difficulty")) - tmp.difficulty = toInt(ho["difficulty"]); - if (ho.count("number")) - tmp.number = toInt(ho["number"]); - if (ho.count("gasLimit")) - tmp.gasLimit = toInt(ho["gasLimit"]); - if (ho.count("gasUsed")) - tmp.gasUsed = toInt(ho["gasUsed"]); - if (ho.count("timestamp")) - tmp.timestamp() = toInt(ho["timestamp"]); - if (ho.count("extraData")) - tmp.extraData() = importByteArray(ho["extraData"].get_str()); + BlockHeader tmp = constructHeader( + ho.count("parentHash") ? h256(ho["parentHash"].get_str()) : h256{}, + ho.count("uncleHash") ? h256(ho["uncleHash"].get_str()) : EmptyListSHA3, + ho.count("coinbase") ? Address(ho["coinbase"].get_str()) : Address{}, + ho.count("stateRoot") ? h256(ho["stateRoot"].get_str()): h256{}, + ho.count("transactionsTrie") ? h256(ho["transactionsTrie"].get_str()) : EmptyTrie, + ho.count("receiptTrie") ? h256(ho["receiptTrie"].get_str()) : EmptyTrie, + ho.count("bloom") ? LogBloom(ho["bloom"].get_str()) : LogBloom{}, + ho.count("difficulty") ? toInt(ho["difficulty"]) : u256(0), + ho.count("number") ? toInt(ho["number"]) : u256(0), + ho.count("gasLimit") ? toInt(ho["gasLimit"]) : u256(0), + ho.count("gasUsed") ? toInt(ho["gasUsed"]) : u256(0), + ho.count("timestamp") ? toInt(ho["timestamp"]) : u256(0), + ho.count("extraData") ? importByteArray(ho["extraData"].get_str()) : bytes{}); // find new valid nonce - if (tmp != _header && tmp.difficulty) + if (static_cast(tmp) != static_cast(_header) && tmp.difficulty()) mine(tmp); + if (ho.count("mixHash")) - tmp.mixHash = h256(ho["mixHash"].get_str()); + updateEthashSeal(tmp, h256(ho["mixHash"].get_str()), tmp.nonce()); if (ho.count("nonce")) - tmp.nonce = Nonce(ho["nonce"].get_str()); + updateEthashSeal(tmp, tmp.mixHash(), Nonce(ho["nonce"].get_str())); tmp.noteDirty(); _header = tmp; @@ -703,19 +698,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) // take the blockheader as is const bytes c_blockRLP = createBlockRLPFromFields(ho); const RLP c_bRLP(c_blockRLP); - _header.populateFromHeader(c_bRLP, IgnoreNonce); + _header.populateFromHeader(c_bRLP, IgnoreSeal); } } -BlockInfo constructBlock(mObject& _o) +BlockHeader constructBlock(mObject& _o, h256 const& _stateRoot) { - BlockInfo ret; + BlockHeader ret; try { // construct genesis block const bytes c_blockRLP = createBlockRLPFromFields(_o); const RLP c_bRLP(c_blockRLP); - ret.populateFromHeader(c_bRLP, IgnoreNonce); + ret.populateFromHeader(c_bRLP, IgnoreSeal); } catch (Exception const& _e) { @@ -732,7 +727,7 @@ BlockInfo constructBlock(mObject& _o) return ret; } -void updatePoW(BlockInfo& _bi) +void updatePoW(BlockHeader& _bi) { mine(_bi); _bi.noteDirty(); @@ -749,7 +744,7 @@ mArray writeTransactionsToJson(Transactions const& txs) return txArray; } -mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) +mObject writeBlockHeaderToJson(mObject& _o, BlockHeader const& _bi) { _o["parentHash"] = toString(_bi.parentHash()); _o["uncleHash"] = toString(_bi.sha3Uncles()); @@ -758,22 +753,22 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) _o["transactionsTrie"] = toString(_bi.transactionsRoot()); _o["receiptTrie"] = toString(_bi.receiptsRoot()); _o["bloom"] = toString(_bi.logBloom()); - _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); + _o["difficulty"] = toCompactHex(_bi.difficulty(), HexPrefix::Add, 1); _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); - _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); - _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); + _o["gasLimit"] = toCompactHex(_bi.gasLimit(), HexPrefix::Add, 1); + _o["gasUsed"] = toCompactHex(_bi.gasUsed(), HexPrefix::Add, 1); _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); - _o["mixHash"] = toString(_bi.mixHash); - _o["nonce"] = toString(_bi.nonce); + _o["mixHash"] = toString(_bi.mixHash()); + _o["nonce"] = toString(_bi.nonce()); _o["hash"] = toString(_bi.hash()); return _o; } -RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs, bytes const& _uncles) +RLPStream createFullBlockFromHeader(BlockHeader const& _bi, bytes const& _txs, bytes const& _uncles) { RLPStream rlpStream; - _bi.streamRLP(rlpStream, WithNonce); + _bi.streamRLP(rlpStream, WithProof); RLPStream ret(3); ret.appendRaw(rlpStream.out()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 39997572f..a8bc852f0 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hash(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index 45c2fa13e..825ed8b4b 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -63,7 +63,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) try { Listener::ExecTimeGuard guard{i.first}; - output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index badabd70c..36f22734f 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -102,13 +102,26 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash() = h256(_o["previousHash"].get_str()); - currentBlock.number = toInt(_o["currentNumber"]); - lastHashes = test::lastHashes(currentBlock.number); - currentBlock.gasLimit = toInt(_o["currentGasLimit"]); - currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); + + RLPStream rlpStream; + rlpStream.appendList(BlockInfo::BasicFields); + + rlpStream << h256(_o["previousHash"].get_str()); + rlpStream << EmptyListSHA3; + rlpStream << Address(_o["currentCoinbase"].get_str()); + rlpStream << h256(); // stateRoot + rlpStream << EmptyTrie; // transactionTrie + rlpStream << EmptyTrie; // receiptTrie + rlpStream << LogBloom(); // bloom + rlpStream << toInt(_o["currentDifficulty"]); + rlpStream << toInt(_o["currentNumber"]); + rlpStream << toInt(_o["currentGasLimit"]); + rlpStream << 0; //gasUsed + rlpStream << toInt(_o["currentTimestamp"]); + rlpStream << std::string(); //extra data + currentBlock = BlockInfo(rlpStream.out(), CheckEverything, h256{}, HeaderData); + + lastHashes = test::lastHashes(currentBlock.number()); } mObject FakeExtVM::exportState() From 855ba20a0fdddc5ed4f1cc58c04b43ca91340375 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 18 Jul 2015 16:08:49 +0200 Subject: [PATCH 083/113] fixed ethashcl build --- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 12 ++++++------ libethereum/Client.h | 2 +- libp2p/Host.cpp | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 8d5264361..cf3a9820e 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -75,7 +75,7 @@ DEV_SIMPLE_EXCEPTION(NoHashRecorded); * The default constructor creates an empty object, which can be tested against with the boolean * conversion operator. */ -struct BlockInfo +class BlockInfo { friend class BlockChain; public: diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index ee483aa8b..09c6cbe19 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -196,7 +196,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, unsigned, unsigned, unsigned, bool, unsigned, boost::optional) { return false; } + static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: @@ -234,7 +234,7 @@ public: unsigned _deviceId, bool _allowCPU, unsigned _extraGPUMemory, - boost::optional _currentBlock + uint64_t _currentBlock ); static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } @@ -246,7 +246,7 @@ private: void workLoop() override; bool report(uint64_t _nonce); - using Miner::accumulateHashes; + using GenericMiner::accumulateHashes; EthashCLHook* m_hook = nullptr; ethash_cl_miner* m_miner = nullptr; @@ -448,7 +448,7 @@ std::string EthashCPUMiner::platformInfo() class EthashCLHook: public ethash_cl_miner::search_hook { public: - EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {} EthashCLHook(EthashCLHook const&) = delete; void abort() @@ -511,7 +511,7 @@ unsigned EthashGPUMiner::s_deviceId = 0; unsigned EthashGPUMiner::s_numInstances = 0; EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): - Miner(_ci), + GenericMiner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { @@ -527,7 +527,7 @@ EthashGPUMiner::~EthashGPUMiner() bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = EthashAux::eval(work().seedHash, work().headerHash, n); + EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n); if (r.value < work().boundary) return submitProof(Solution{n, r.mixHash}); return false; diff --git a/libethereum/Client.h b/libethereum/Client.h index 4523d324b..18ac1c648 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -337,7 +337,7 @@ public: { m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); m_sealEngine->onSealGenerated([=](bytes const& header){ - return this->submitSealed(header); + this->submitSealed(header); }); init(_host, _dbPath, _forceAction, _networkId); } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index d57741e61..30306e3f5 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -627,7 +627,7 @@ void Host::run(boost::system::error_code const&) m_nodeTable->processEvents(); // cleanup zombies - DEV_GUARDED(x_connecting); + DEV_GUARDED(x_connecting) m_connecting.remove_if([](std::weak_ptr h){ return h.expired(); }); DEV_GUARDED(x_timers) m_timers.remove_if([](std::shared_ptr t) From b374a02be74517d8f6c86c80d0784999e1ea8987 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jul 2015 18:43:39 +0200 Subject: [PATCH 084/113] Avoid rescuing beyond genesis. Closes #2505 --- libethereum/BlockChain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 8a654fa51..2b6cb25c2 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -849,7 +849,7 @@ void BlockChain::rescue(OverlayDB& _db) u = m; } cout << " lowest is " << l << endl; - for (;; --l) + for (; l > 0; --l) { h256 h = numberHash(l); cout << "Checking validity of " << l << " (" << h << ")..." << flush; From 34dc98b21028dae8bdb91973c1dafedfd6660d1f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jul 2015 19:02:59 +0200 Subject: [PATCH 085/113] Build ETHASHCL by default. Closes #2497. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d3c167a..3330977aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ option(GUI "Build GUI components (AlethZero, Mix)" ON) option(TESTS "Build the tests." ON) option(NOBOOST "No use of boost macros in test functions" OFF) option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF) -option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF) +option(ETHASHCL "Build in support for GPU mining via OpenCL" ON) option(JSCONSOLE "Build in javascript console" ON) # propagates CMake configuration options to the compiler From fdaf2a7653e1ffd31e82d4757c881c674d17451e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jul 2015 19:15:45 +0200 Subject: [PATCH 086/113] Fix for stateroot in tests. --- test/libethereum/blockchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 6d4761bb9..764585520 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -708,7 +708,7 @@ BlockHeader constructBlock(mObject& _o, h256 const& _stateRoot) try { // construct genesis block - const bytes c_blockRLP = createBlockRLPFromFields(_o); + const bytes c_blockRLP = createBlockRLPFromFields(_o, _stateRoot); const RLP c_bRLP(c_blockRLP); ret.populateFromHeader(c_bRLP, IgnoreSeal); } From 32c11d96641610cd11eed3ff19843ee86f7b3399 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jul 2015 18:59:19 -0700 Subject: [PATCH 087/113] Modularise nonce, mix hash and seed hash. --- alethzero/MainWin.cpp | 4 +-- ethminer/MinerAux.h | 10 +++---- exp/main.cpp | 2 +- libethcore/BlockInfo.cpp | 45 +++++++++++++----------------- libethcore/BlockInfo.h | 26 +++++++++--------- libethcore/Common.cpp | 5 ++-- libethcore/Common.h | 1 + libethcore/Ethash.cpp | 52 ++++++++++++++++++++++++++++------- libethcore/Ethash.h | 16 +++++++++-- libethcore/EthashAux.cpp | 7 ++++- libethcore/EthashAux.h | 2 +- libethcore/ProofOfWork.h | 1 - libethereum/BlockChain.cpp | 8 +++--- libethereum/BlockQueue.cpp | 12 ++++---- libethereum/State.cpp | 8 +++--- libethereum/State.h | 4 +-- libweb3jsonrpc/JsonHelper.cpp | 7 +++-- mix/MixClient.cpp | 1 - test/TestHelper.cpp | 2 +- 19 files changed, 128 insertions(+), 85 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e48b58283..4655240e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1718,7 +1718,7 @@ void Main::on_blocks_currentItemChanged() s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { @@ -1749,7 +1749,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ff28132b1..5c6112743 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -254,17 +254,17 @@ public: bi.difficulty = u256(m); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bi.proof.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; exit(0); } catch (...) @@ -382,7 +382,7 @@ private: { BlockInfo bi; bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/exp/main.cpp b/exp/main.cpp index 88608f8cf..9884bd0e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -197,7 +197,7 @@ int main() bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, bi); + bi.proof = sol; return completed = true; }); f.setWork(bi); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index fec5b4678..c7acd9091 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -26,7 +26,6 @@ #include #include #include "EthashAux.h" -#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -57,22 +56,21 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - mixHash = h256(); - nonce = Nonce(); - m_hash = m_seedHash = h256(); + proof = ProofOfWork::Solution(); + m_proofCache = ProofOfWork::HeaderCache(); + m_hash = h256(); } -h256 const& BlockInfo::seedHash() const +ProofOfWork::HeaderCache const& BlockInfo::proofCache() const { - if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); - return m_seedHash; + ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); + return m_proofCache; } h256 const& BlockInfo::hash() const { if (!m_hash) - m_hash = headerHash(WithNonce); + m_hash = headerHash(WithProof); return m_hash; } @@ -90,20 +88,20 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const return ret; } -h256 BlockInfo::headerHash(IncludeNonce _n) const +h256 BlockInfo::headerHash(IncludeProof _n) const { RLPStream s; streamRLP(s, _n); return sha3(s.out()); } -void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const +void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const { - _s.appendList(_n == WithNonce ? 15 : 13) + _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithNonce) - _s << mixHash << nonce; + if (_n == WithProof) + proof.streamRLP(_s); } h256 BlockInfo::headerHash(bytesConstRef _block) @@ -116,12 +114,12 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); - m_seedHash = h256(); + m_proofCache = ProofOfWork::HeaderCache(); int field = 0; try { - if (_header.itemCount() != 15) + if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); @@ -136,8 +134,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - mixHash = _header[field = 13].toHash(RLP::VeryStrict); - nonce = _header[field = 14].toHash(RLP::VeryStrict); + proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -152,22 +149,18 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ProofOfWork::composeException(ex, *this); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); - ex << errinfo_seedHash(seedHash()); ex << errinfo_target(boundary()); - ex << errinfo_mixHash(mixHash); - Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce); - ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); BOOST_THROW_EXCEPTION(ex); } else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); + ProofOfWork::composeExceptionPre(ex, *this); BOOST_THROW_EXCEPTION(ex); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 79c12ebb4..b77c47c6b 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -24,16 +24,17 @@ #include #include #include "Common.h" +#include "ProofOfWork.h" namespace dev { namespace eth { -enum IncludeNonce +enum IncludeProof { - WithoutNonce = 0, - WithNonce = 1 + WithoutProof = 0, + WithProof = 1 }; enum Strictness @@ -82,8 +83,7 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - h256 mixHash; - Nonce nonce; + typename ProofOfWork::Solution proof; BlockInfo(); explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} @@ -112,14 +112,13 @@ public: gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && extraData == _cmp.extraData && - mixHash == _cmp.mixHash && - nonce == _cmp.nonce; + proof == _cmp.proof; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } void clear(); - void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); } + void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); @@ -130,16 +129,17 @@ public: u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - h256 const& seedHash() const; + ProofOfWork::HeaderCache const& proofCache() const; h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeNonce _n) const; - void streamRLP(RLPStream& _s, IncludeNonce _n) const; + h256 headerHash(IncludeProof _n) const; + void streamRLP(RLPStream& _s, IncludeProof _n) const; private: - mutable h256 m_seedHash; + + mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; @@ -148,7 +148,7 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; + _bi.gasUsed << " " << _bi.timestamp; return _out; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 618703e22..41cd1bba8 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -26,6 +26,7 @@ #include #include "Exceptions.h" #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -112,9 +113,9 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset; string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; - string const c_space = c_border + string(76, ' ') + c_border; + string const c_space = c_border + string(76, ' ') + c_border + EthReset; stringstream ss; ss << c_line << endl; ss << c_space << endl; diff --git a/libethcore/Common.h b/libethcore/Common.h index 296f0d01d..1e0cdc3b1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -189,6 +189,7 @@ struct TransactionSkeleton Address to; u256 value; bytes data; + u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; u256 nonce = UndefinedU256; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9be76926d..6a4a1445f 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -46,6 +46,7 @@ #endif #include "BlockInfo.h" #include "EthashAux.h" +#include "Exceptions.h" using namespace std; using namespace std::chrono; @@ -56,6 +57,26 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); +void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +{ + if (!io_out) + io_out = EthashAux::seedHash((unsigned)_h.number); +} + +void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); + _ex << errinfo_mixHash(_bi.proof.mixHash); + _ex << errinfo_seedHash(_bi.proofCache()); + Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); + _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +} + +void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); +} + std::string Ethash::name() { return "Ethash"; @@ -66,12 +87,23 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) +{ + mixHash = _header[_field].toHash(RLP::VeryStrict); + nonce = _header[++_field].toHash(RLP::VeryStrict); +} + +void Ethash::Solution::streamRLP(RLPStream& io_rlp) const +{ + io_rlp << mixHash << nonce; +} + Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutNonce); - ret.seedHash = _bi.seedHash(); + ret.headerHash = _bi.headerHash(WithoutProof); + ret.seedHash = _bi.proofCache(); return ret; } @@ -84,7 +116,7 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { - EthashAux::full(_header.seedHash(), true, _f); + EthashAux::full(_header.proofCache(), true, _f); } bool Ethash::preVerify(BlockInfo const& _header) @@ -95,9 +127,9 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), + (uint64_t)(u64)_header.proof.nonce, + (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); return ret; @@ -115,7 +147,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -125,9 +157,9 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; + cwarn << "headerHash:" << _header.headerHash(WithoutProof); + cwarn << "nonce:" << _header.proof.nonce; + cwarn << "mixHash:" << _header.proof.mixHash; cwarn << "difficulty:" << _header.difficulty; cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 7ffd887d0..5640152f0 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -28,16 +28,20 @@ #include #include #include "Common.h" -#include "BlockInfo.h" #include "Miner.h" class ethash_cl_miner; namespace dev { + +class RLP; +class RLPStream; + namespace eth { +class BlockInfo; class EthashCLHook; class Ethash @@ -45,8 +49,17 @@ class Ethash public: using Miner = GenericMiner; + using HeaderCache = h256; + static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); + static void composeException(Exception& _ex, BlockInfo& _bi); + static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + struct Solution { + bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } + void populateFromRLP(RLP const& io_rlp, int& io_field); + void streamRLP(RLPStream& io_rlp) const; + static const unsigned Fields = 2; Nonce nonce; h256 mixHash; }; @@ -78,7 +91,6 @@ public: static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } class CPUMiner: public Miner, Worker { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index efb6066f7..db01f3c49 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,6 +200,11 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } +Ethash::Result EthashAux::eval(BlockInfo const& _header) +{ + return eval(_header, _header.proof.nonce); +} + #define DEV_IF_THROWS(X) try { X; } catch (...) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) @@ -252,7 +257,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { - return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); + return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index d5bd60d44..be07f579c 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -78,7 +78,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 764207aef..7b4298047 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -38,7 +38,6 @@ namespace eth * typename Solution * typename CPUMiner * typename GPUMiner - * void assignResult(BlockInfo&, Result) * and a few others. TODO */ using ProofOfWork = Ethash; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 768ed223f..aaafe7ce9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -575,8 +575,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash.abridged() @@ -666,8 +666,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f95a3880e..690fb60ee 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.hash; + bi.proof.mixHash = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.mixHash == work.hash) + if (it->verified.info.proof.mixHash == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.mixHash == work.hash) + if (i.verified.info.proof.mixHash == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..bf55a50ff 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -837,7 +837,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); + m_currentBlock.streamRLP(block, WithProof); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -902,7 +902,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithNonce); + ubi.streamRLP(unclesData, WithProof); ++unclesCount; uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) @@ -970,7 +970,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithNonce); + m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -978,7 +978,7 @@ void State::completeMine() cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.nonce.abridged(), + m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() ); diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..0555b6dcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -169,11 +169,11 @@ public: if (!m_committedToMine) return false; - PoW::assignResult(_result, m_currentBlock); + m_currentBlock.proof = _result; if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..f7c09ebc2 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -99,11 +99,12 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["gasLimit"] = toJS(_bi.gasLimit); res["timestamp"] = toJS(_bi.timestamp); res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); res["logsBloom"] = toJS(_bi.logBloom); - - res["seedHash"] = toJS(_bi.seedHash()); res["target"] = toJS(_bi.boundary()); + + // TODO: move into ProofOfWork. + res["nonce"] = toJS(_bi.proof.nonce); + res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 8373c7c51..ea4686601 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -49,7 +49,6 @@ namespace struct MixPow //dummy POW { typedef int Solution; - static void assignResult(int, BlockInfo const&) {} static bool verify(BlockInfo const&) { return true; } }; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f49ed1e09..b43c4db51 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(BlockInfo& _bi) bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, _bi); + _bi.proof = sol; return completed = true; }); f.setWork(_bi); From 0c5e924745211793de1ebfccbc518bef6872347e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 13:03:52 -0700 Subject: [PATCH 088/113] Basic Proof-of-Authority sealent. --- eth/main.cpp | 3 + ethminer/MinerAux.h | 28 +++++++-- libdevcrypto/Common.cpp | 5 ++ libdevcrypto/Common.h | 3 + libethcore/Common.cpp | 4 ++ libethcore/Common.h | 13 +++- libethcore/Ethash.cpp | 26 +++++++- libethcore/Ethash.h | 31 +++++++++ libethcore/EthashAux.cpp | 11 ++++ libethcore/EthashAux.h | 1 + libethcore/Farm.h | 1 - libethcore/Miner.h | 11 ---- libethcore/ProofOfWork.cpp | 25 ++++++++ libethcore/ProofOfWork.h | 76 ++++++++++++++++++++++- libethereum/BlockChain.cpp | 4 ++ libethereum/BlockQueue.cpp | 12 ++-- libethereum/Client.cpp | 15 +---- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 +- libethereum/State.h | 2 +- libweb3jsonrpc/JsonHelper.cpp | 2 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 10 ++- 22 files changed, 246 insertions(+), 43 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 5b38f2779..434860f59 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1700,7 +1700,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) { From 076e5c03eeb48f8042509c43a2329ca3a08ffcf8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH 089/113] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + 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 BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + 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 BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - 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); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) 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)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); - _ex << errinfo_mixHash(_bi.proof.mixHash); - _ex << errinfo_seedHash(_bi.proofCache()); - Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); - _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); -#else - (void)_ex; - (void)_bi; -#endif -} - -void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) -{ -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); -#else - (void)_ex; - (void)_bi; -#endif -} - -std::string Ethash::name() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) -{ - WorkPackage ret; - ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutProof); -#if ETH_USING_ETHASH - ret.seedHash = _bi.proofCache(); -#endif - return ret; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -void Ethash::prep(BlockInfo const& _header, std::function const& _f) -{ -#if ETH_USING_ETHASH - EthashAux::full(_header.proofCache(), true, _f); -#else - (void)_header; - (void)_f; -#endif + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (number >= ETHASH_EPOCH_LENGTH * 2048) return false; -#if ETH_USING_ETHASH - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ bool Ethash::verify(BlockInfo const& _header) } #endif -#if ETH_USING_ETHASH - auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + 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, unsigned, 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 + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - 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, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#else - using GPUMiner = CPUMiner; -#endif /// Default value of the local work size. Also known as workgroup size. static const unsigned defaultLocalWorkSize; /// Default value of the global work size as a multiplier of the local work size static const unsigned defaultGlobalWorkSizeMultiplier; /// Default value of the milliseconds per global work size (per batch) static const unsigned defaultMSPerBatch; - - struct Farm: public eth::GenericFarm - { - public: - strings sealers() const { return { "cpu", "opencl" }; } - void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } - - void sealBlock(BlockInfo const& _bi) - { - setWork(_bi); - if (m_opencl) - startGPU(); - else - startCPU(); - - setWork(_bi); - ensurePrecomputed((unsigned)_bi.number); - } - - void disable() { stop(); } - - private: - bool m_opencl = false; - }; }; } diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) - return true; - m_miners.clear(); - m_miners.reserve(MinerType::instances()); - for (unsigned i = 0; i < MinerType::instances(); ++i) - { - m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); - -bool BasicAuthority::verify(BlockInfo const& _header) -{ - return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; -} - -bool BasicAuthority::preVerify(BlockInfo const& _header) -{ - return SignatureStruct(_header.proof.sig).isValid(); -} - -BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) -{ - return WorkPackage{_header.headerHash(WithoutProof)}; -} - -void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) -{ - m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); -} - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -class BasicAuthority -{ -public: - struct HeaderCache {}; - static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} - static void composeException(Exception&, BlockInfo&) {} - static void composeExceptionPre(Exception&, BlockInfo&) {} - - struct Solution - { - bool operator==(Solution const& _v) const { return sig == _v.sig; } - void populateFromRLP(RLP const& io_rlp, int& io_field) - { - sig = io_rlp[io_field++].toHash(RLP::VeryStrict); - } - - void streamRLP(RLPStream& io_rlp) const - { - io_rlp << sig; - } - static const unsigned Fields = 1; - Signature sig; - }; - - struct Result - { - Signature sig; - }; - - struct WorkPackage - { - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } - - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - }; - - static const WorkPackage NullWorkPackage; - - static std::string name() { return "BasicAuthority"; } - static unsigned revision() { return 0; } - static void prep(BlockInfo const&, std::function const& = std::function()) {} - static void ensurePrecomputed(unsigned) {} - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - static const Address Authority; - - struct Farm - { - public: - strings sealers() const { return { "default" }; } - void setSealer(std::string const&) {} - void setSecret(Secret const& _s) { m_secret = _s; } - void sealBlock(BlockInfo const& _bi); - void disable() {} - void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } - - private: - Secret m_secret; - std::function m_onSolutionFound; - }; -}; - using ProofOfWork = BasicAuthority; } diff --git a/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + 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 Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + 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 Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady; From 3fa8cfc3285544d8d8163c63bb0476489cde6f9b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Jul 2015 16:32:04 -0700 Subject: [PATCH 090/113] Tests working for BasicAuthority and Ethash. --- CMakeLists.txt | 32 ++++++++++++++-------------- exp/CMakeLists.txt | 20 ++++++++++++------ exp/main.cpp | 40 ++++++++++++++++++++++++++--------- libdevcore/Common.h | 1 + libethcore/BasicAuthority.cpp | 18 +++++++++++++--- libethcore/BasicAuthority.h | 7 +++++- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 1 + libethcore/EthashAux.cpp | 23 -------------------- libethcore/EthashAux.h | 2 -- libethcore/Sealer.h | 12 +++++++++++ 12 files changed, 97 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d3c167a..1d35280e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,13 +403,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) - add_subdirectory(libweb3jsonrpc) +# add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) - add_subdirectory(libjsengine) - add_subdirectory(libjsconsole) - add_subdirectory(ethconsole) +# add_subdirectory(libjsengine) +# add_subdirectory(libjsconsole) +# add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -435,33 +435,33 @@ endif () add_subdirectory(libethcore) if (GENERAL) - add_subdirectory(libevm) - add_subdirectory(libethereum) - add_subdirectory(libwebthree) +# add_subdirectory(libevm) +# add_subdirectory(libethereum) +# add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) - add_subdirectory(ethminer) +# add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) - add_subdirectory(ethkey) +# add_subdirectory(ethkey) endif () if (TESTS) - add_subdirectory(libtestutils) - add_subdirectory(test) +# add_subdirectory(libtestutils) +# add_subdirectory(test) if (JSONRPC) - add_subdirectory(ethrpctest) +# add_subdirectory(ethrpctest) endif () endif () if (TOOLS) - add_subdirectory(rlp) - add_subdirectory(abi) - add_subdirectory(ethvm) - add_subdirectory(eth) +# add_subdirectory(rlp) +# add_subdirectory(abi) +# add_subdirectory(ethvm) +# add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 7a80023bf..30f4705f9 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,15 +18,21 @@ if (READLINE_FOUND) endif() if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) +# target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} p2p) +#target_link_libraries(${EXECUTABLE} webthree) +#target_link_libraries(${EXECUTABLE} ethereum) +#target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} ethash) - target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} ethash-cl) +# target_link_libraries(${EXECUTABLE} ethash) +# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) endif() +target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) + + + + + diff --git a/exp/main.cpp b/exp/main.cpp index 07eee6a11..fa8603459 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,6 +70,7 @@ namespace fs = boost::filesystem; #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -80,24 +81,43 @@ using namespace eth; int main() { BlockInfo bi; + bi.difficulty = c_genesisDifficulty; + bi.gasLimit = c_genesisGasLimit; + bi.number = 1; + bi.parentHash = sha3("parentHash"); + bytes sealedData; - SealEngineFace* se = BasicAuthority::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); - se->generateSeal(bi); { + KeyPair kp(sha3("test")); + SealEngineFace* se = BasicAuthority::createSealEngine(); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); + cdebug << se->sealers(); + bool done = false; + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.sig(); } - SealEngineFace* se = Ethash::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); - se->generateSeal(bi); - while (!done) - this_thread::sleep_for(chrono::milliseconds(50)); { + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + bool done = false; + se->setSealer("cpu"); + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.nonce(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 303512e57..612b7c685 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using byte = uint8_t; #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) namespace dev { diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index bbf4e3f2a..7006107e1 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); +AddressHash BasicAuthority::s_authorities; bool BasicAuthority::BlockHeaderRaw::verify() const { - return toAddress(recover(m_sig, hashWithout())) == Authority; + return s_authorities.count(toAddress(recover(m_sig, hashWithout()))); } bool BasicAuthority::BlockHeaderRaw::preVerify() const @@ -94,11 +94,23 @@ public: MiningProgress miningProgress() const { return MiningProgress(); } private: + virtual bool onOptionChanging(std::string const& _name, bytes const& _value) + { + RLP rlp(_value); + if (_name == "authorities") + BasicAuthority::s_authorities = rlp.toUnorderedSet
(); + else if (_name == "authority") + m_secret = rlp.toHash(); + else + return false; + return true; + } + Secret m_secret; std::function m_onSealGenerated; }; -SealEngineFace* createSealEngine() +SealEngineFace* BasicAuthority::createSealEngine() { return new BasicAuthoritySealEngine; } diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 616c18340..9127c1d53 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -30,6 +30,7 @@ #include "Sealer.h" class BasicAuthoritySeal; +class BasicAuthoritySealEngine; namespace dev { @@ -48,6 +49,8 @@ namespace eth */ class BasicAuthority { + friend class ::BasicAuthoritySealEngine; + public: // TODO: remove struct Result {}; @@ -70,6 +73,7 @@ public: Signature sig() const { return m_sig; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 1; @@ -84,7 +88,8 @@ public: }; using BlockHeader = BlockHeaderPolished; - static const Address Authority; +private: + static AddressHash s_authorities; }; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index cd55bc1f6..710279cb2 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -158,7 +158,7 @@ public: explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c3f19e723..d385163be 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -119,7 +119,7 @@ bool Ethash::BlockHeaderRaw::verify() const } #endif - auto result = EthashAux::eval(*this); + auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce); bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); @@ -281,6 +281,7 @@ public: { m_farm.onSolutionFound([=](Ethash::Solution const& sol) { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; EthashSeal s(sol.mixHash, sol.nonce); _f(&s); return true; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index eee0e3881..99baa8a05 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -94,6 +94,7 @@ public: h256 const& mixHash() const { return m_mixHash; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 2; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 42a3cf6fb..00537c21a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,18 +200,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } -Ethash::Result EthashAux::eval(BlockInfo const& _header) -{ -#if ETH_USING_ETHASH - return eval(_header, _header.proof.nonce); -#else - (void)_header; - return Ethash::Result(); -#endif -} - -#define DEV_IF_THROWS(X) try { X; } catch (...) - unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); @@ -260,17 +248,6 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) -{ -#if ETH_USING_ETHASH - return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); -#else - (void)_header; - (void)_nonce; - return Ethash::Result(); -#endif -} - Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 5ae24898d..132b9b436 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -79,8 +79,6 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header); - static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index f491240f3..28381444e 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include "Common.h" namespace dev @@ -43,6 +44,9 @@ public: class SealEngineFace { public: + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; @@ -52,6 +56,14 @@ public: // TODO: rename & generalise virtual bool isMining() const { return false; } virtual MiningProgress miningProgress() const { return MiningProgress(); } + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; }; } From 58c7d1ead6023af005b66383b477bbf1b587e792 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jul 2015 23:24:10 +0200 Subject: [PATCH 091/113] Basic test working with same code for Ethash and BasicAuthority. --- CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 1 - ethminer/MinerAux.h | 17 +-- exp/CMakeLists.txt | 6 +- exp/main.cpp | 86 +++++++------ libdevcore/Guards.h | 29 +++++ libdevcore/RLP.h | 3 + libdevcore/TrieDB.h | 9 +- libethcore/BasicAuthority.cpp | 43 ++++--- libethcore/BasicAuthority.h | 16 +-- libethcore/BlockInfo.cpp | 34 +---- libethcore/BlockInfo.h | 64 ++++++--- libethcore/Common.cpp | 3 +- libethcore/Common.h | 14 +- libethcore/Ethash.cpp | 163 ++++++++++++----------- libethcore/Ethash.h | 52 ++------ libethcore/EthashAux.cpp | 17 ++- libethcore/EthashAux.h | 47 ++++++- libethcore/Farm.h | 6 +- libethcore/Miner.h | 4 +- libethcore/ProofOfWork.cpp | 27 ---- libethcore/ProofOfWork.h | 40 ------ libethcore/Sealer.h | 31 +++-- libethereum/BlockChain.cpp | 136 ++++++++++---------- libethereum/BlockChain.h | 113 ++++++++++++++-- libethereum/BlockChainSync.cpp | 11 +- libethereum/BlockQueue.cpp | 24 ++-- libethereum/BlockQueue.h | 8 +- libethereum/CanonBlockChain.cpp | 75 ++++++----- libethereum/CanonBlockChain.h | 45 ++++++- libethereum/Client.cpp | 200 ++++++++++++++++------------- libethereum/Client.h | 119 +++++++++++------ libethereum/ClientBase.cpp | 2 +- libethereum/ClientBase.h | 4 +- libethereum/Interface.h | 8 +- libethereum/State.cpp | 87 ++++++------- libethereum/State.h | 66 ++++------ libethereum/Utility.cpp | 4 +- libethereum/Utility.h | 3 +- libweb3jsonrpc/JsonHelper.cpp | 6 +- libweb3jsonrpc/JsonHelper.h | 14 ++ test/libethcore/dagger.cpp | 3 +- test/libethereum/stateOriginal.cpp | 3 +- 44 files changed, 933 insertions(+), 716 deletions(-) delete mode 100644 libethcore/ProofOfWork.cpp delete mode 100644 libethcore/ProofOfWork.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d35280e0..b410d875c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,8 +435,8 @@ endif () add_subdirectory(libethcore) if (GENERAL) -# add_subdirectory(libevm) -# add_subdirectory(libethereum) + add_subdirectory(libevm) + add_subdirectory(libethereum) # add_subdirectory(libwebthree) endif () diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4655240e3..2ee8928f5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -208,7 +208,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); diff --git a/eth/main.cpp b/eth/main.cpp index 434860f59..7ce4d49c2 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 051128669..61fde605d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #if ETH_ETHASHCL || !ETH_TRUE @@ -387,7 +386,6 @@ public: #endif } -#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -412,10 +410,10 @@ private: genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - GenericFarm f; - f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + GenericFarm f; + f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); - string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; @@ -488,20 +486,20 @@ private: jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; + GenericFarm f; if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) f.startGPU(); - ProofOfWork::WorkPackage current; + EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; while (true) try { bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) + EthashProofOfWork::Solution solution; + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { solution = sol; return completed = true; @@ -595,5 +593,4 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; -#endif }; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 30f4705f9..5f876a69b 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -22,12 +22,12 @@ if (JSONRPC) endif() #target_link_libraries(${EXECUTABLE} webthree) -#target_link_libraries(${EXECUTABLE} ethereum) -#target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) # target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash) -# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} OpenCL) endif() target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/exp/main.cpp b/exp/main.cpp index fa8603459..4a35068f1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -71,13 +70,16 @@ namespace fs = boost::filesystem; #include #include #include +#include +#include +#include +#include using namespace std; using namespace dev; using namespace eth; #endif -#if 1 - +#if 0 int main() { BlockInfo bi; @@ -124,9 +126,7 @@ int main() return 0; } - #elif 0 - int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); @@ -135,10 +135,7 @@ int main() cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); return 0; } - - #elif 0 - int main() { cdebug << "EXP"; @@ -162,9 +159,7 @@ int main() ret = orderedTrieRoot(data); cdebug << ret; } - #elif 0 - int main() { KeyManager keyman; @@ -186,7 +181,6 @@ int main() cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); } - #elif 0 int main() { @@ -246,15 +240,15 @@ int main() #elif 0 int main() { - GenericFarm f; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { BlockInfo bi = g; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { bi.proof = sol; return completed = true; @@ -289,23 +283,16 @@ int main() return 0; } -#elif 0 - -void mine(State& s, BlockChain const& _bc) +#elif 1 +void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) { s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - return completed = s.completeMine(sol); - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + _se->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); } -#elif 0 int main() { cnote << "Testing State..."; @@ -316,47 +303,62 @@ int main() Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; - cout << bc; + using Sealer = Ethash; + CanonBlockChain bc; + auto gbb = bc.headerData(bc.genesisHash()); + assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData)); + + SealEngineFace* se = Sealer::createSealEngine(); + KeyPair kp(sha3("test")); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); - cout << s; + OverlayDB stateDB = State::openDB(bc.genesisHash()); + cnote << bc; + + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); + cnote << s; // Sync up - this won't do much until we use the last state. s.sync(bc); - cout << s; + cnote << s; // Mine to get some ether! - mine(s, bc); + mine(s, bc, se); - bc.attemptImport(s.blockData(), stateDB); + bytes minedBlock = s.blockData(); + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + bc.import(minedBlock, stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; + cnote << "Miner now has" << s.balance(myMiner.address()); + s.resetCurrent(); + cnote << "Miner now has" << s.balance(myMiner.address()); // Inject a transaction to transfer funds from miner to me. Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); - cout << s; + cnote << s; // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - mine(s, bc); + mine(s, bc, se); bc.attemptImport(s.blockData(), stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; return 0; } diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 44d5969e4..135209d23 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex; using SharedMutex = boost::shared_mutex; using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; using RecursiveGuard = std::lock_guard; using ReadGuard = boost::shared_lock; using UpgradableGuard = boost::upgrade_lock; @@ -74,6 +76,33 @@ private: }; using SpinGuard = std::lock_guard; +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a94c8ba55..701f4b8e8 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -393,6 +393,9 @@ public: /// Read the byte stream. bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + /// Swap the contents of the output stream out for some other byte array. void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..05affa677 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -231,8 +231,11 @@ public: } } -protected: - DB* db() const { return m_db; } + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -383,6 +386,7 @@ public: using Super::isEmpty; using Super::root; + using Super::db; using Super::leftOvers; using Super::check; @@ -435,6 +439,7 @@ public: using Super::check; using Super::open; using Super::setRoot; + using Super::db; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7006107e1..22da67080 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -19,6 +19,7 @@ * @date 2014 */ +#include #include "Exceptions.h" #include "BasicAuthority.h" #include "BlockInfo.h" @@ -60,38 +61,38 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri } } +void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} +void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} -class BasicAuthoritySeal: public SealFace +StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const { -public: - BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + return { { "sig", toJS(m_sig) } }; +} - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - BasicAuthority::BlockHeader h(_bi); - h.m_sig = m_sig; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } -private: - Signature m_sig; -}; -class BasicAuthoritySealEngine: public SealEngineFace +class BasicAuthoritySealEngine: public SealEngineBase { public: void setSecret(Secret const& _s) { m_secret = _s; } void generateSeal(BlockInfo const& _bi) { - BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); - m_onSealGenerated(&s); + BasicAuthority::BlockHeader h(_bi); + h.m_sig = sign(m_secret, _bi.hashWithout()); + RLPStream ret; + h.streamRLP(ret); + m_onSealGenerated(ret.out()); } - void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isWorking() const { return false; } + WorkingProgress workingProgress() const { return WorkingProgress(); } private: virtual bool onOptionChanging(std::string const& _name, bytes const& _value) @@ -107,7 +108,7 @@ private: } Secret m_secret; - std::function m_onSealGenerated; + std::function m_onSealGenerated; }; SealEngineFace* BasicAuthority::createSealEngine() diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 9127c1d53..8db47938b 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -52,33 +52,31 @@ class BasicAuthority friend class ::BasicAuthoritySealEngine; public: - // TODO: remove - struct Result {}; - struct WorkPackage {}; - static const WorkPackage NullWorkPackage; - static std::string name() { return "BasicAuthority"; } static unsigned revision() { return 0; } static SealEngineFace* createSealEngine(); class BlockHeaderRaw: public BlockInfo { - friend class ::BasicAuthoritySeal; + friend class ::BasicAuthoritySealEngine; public: + static const unsigned SealFields = 1; + bool verify() const; bool preVerify() const; - WorkPackage package() const { return NullWorkPackage; } Signature sig() const { return m_sig; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 1; - void populateFromHeader(RLP const& _header, Strictness _s); + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); void streamRLPFields(RLPStream& _s) const { _s << m_sig; } void clear() { m_sig = Signature(); } void noteDirty() const {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb07162fb..64961bc40 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,10 +36,10 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt) { - RLP header = extractHeader(_block); - m_hash = sha3(header.data()); + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); populateFromHeader(header, _s); } @@ -58,7 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - m_hashWithout = h256(); + noteDirty(); } h256 const& BlockInfo::boundary() const @@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing) - { - if (gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); - - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); - - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); - - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); - } + if (_s != CheckNothing && gasUsed > gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) gasLimit = selectGasLimit(_parent); gasUsed = 0; difficulty = calculateDifficulty(_parent); + parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const @@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const void BlockInfo::verifyParent(BlockInfo const& _parent) const { - // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); - - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); - // Check timestamp is after previous timestamp. if (parentHash) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 710279cb2..b00fa73fb 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -42,10 +42,18 @@ enum Strictness { CheckEverything, QuickNonce, - IgnoreNonce, + IgnoreSeal, CheckNothing }; +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); + /** @brief Encapsulation of a block header. * Class to contain all of a block header's data. It is able to parse a block header and populate * from some given RLP block serialisation with the static fromHeader(), through the method @@ -69,7 +77,10 @@ enum Strictness */ struct BlockInfo { + friend class BlockChain; public: + static const unsigned BasicFields = 13; + // TODO: make them all private! h256 parentHash; h256 sha3Uncles; @@ -78,7 +89,7 @@ public: h256 transactionsRoot; h256 receiptsRoot; LogBloom logBloom; - u256 difficulty; + u256 difficulty; // TODO: pull out into BlockHeader u256 number; u256 gasLimit; u256 gasUsed; @@ -86,10 +97,12 @@ public: bytes extraData; BlockInfo(); - BlockInfo(bytesConstRef _block, Strictness _s); + explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); + explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -121,17 +134,14 @@ public: /// sha3 of the header only. h256 const& hashWithout() const; - h256 const& hash() const { return m_hash; } - -protected: - static RLP extractHeader(bytesConstRef _block); - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); - void streamRLPFields(RLPStream& _s) const; + h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } void clear(); void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } - static const unsigned BasicFields = 13; +protected: + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal); + void streamRLPFields(RLPStream& _s) const; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. @@ -152,35 +162,50 @@ template class BlockHeaderPolished: public BlockInfoSub { public: + static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields; + BlockHeaderPolished() {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} - explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } - explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); } + explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); } - static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } + // deprecated - just use constructor instead. + static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } + static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } - void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + // deprecated for public API - use constructor. + // TODO: make private. + void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData) + { + populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h); + } void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); BlockInfo::parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); + BlockInfoSub::populateFromParent(_parent); } + // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); + BlockInfoSub::verifyParent(_parent); } - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + // deprecated for public API - use constructor. + // TODO: make private. + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { BlockInfo::m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); + else + BlockInfo::m_hash = dev::sha3(_header.data()); if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); @@ -213,6 +238,13 @@ public: if (_i == WithProof) BlockInfoSub::streamRLPFields(_s); } + + bytes sealFieldsRLP() const + { + RLPStream s; + BlockInfoSub::streamRLPFields(s); + return s.out(); + } }; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 58e506b37..499854584 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -29,7 +29,6 @@ #include #include #include "Exceptions.h" -#include "ProofOfWork.h" #include "BlockInfo.h" using namespace std; using namespace dev; @@ -57,7 +56,7 @@ Network const c_network = Network::Frontier; Network const c_network = Network::Olympic; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 1a688fbd8..5c0a0cc79 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -124,10 +124,16 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, ///< Validate nonce + ValidSeal = 1, ///< Validate seal DontHave = 2, ///< Avoid old blocks - CheckUncles = 4, ///< Check uncle nonces - Default = ValidNonce | DontHave | CheckUncles + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures + Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + None = 0 }; }; @@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(& /** * @brief Describes the progress of a mining operation. */ -struct MiningProgress +struct WorkingProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index d385163be..128822b80 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "Exceptions.h" #include "Farm.h" #include "Miner.h" +#include "Params.h" using namespace std; using namespace std::chrono; @@ -57,8 +59,6 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); - h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) @@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); ex << errinfo_mixHash(m_mixHash); ex << errinfo_seedHash(seedHash()); - Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); ex << errinfo_difficulty(difficulty); @@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } + + if (_s != CheckNothing) + { + if (difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + + if (gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + + if (number && extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + } +} + +void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + + if (gasLimit < c_minGasLimit || + gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || + gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); +} + +void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; } bool Ethash::BlockHeaderRaw::preVerify() const @@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const return slow; } -Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const -{ - WorkPackage ret; - ret.boundary = boundary(); - ret.headerHash = hashWithout(); - ret.seedHash = seedHash(); - return ret; -} - void Ethash::BlockHeaderRaw::prep(std::function const& _f) const { EthashAux::full(seedHash(), true, _f); } +StringHashMap Ethash::BlockHeaderRaw::jsInfo() const +{ + return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; +} @@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function const& _f) const -class EthashCPUMiner: public GenericMiner, Worker +class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -190,7 +214,7 @@ private: }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker +class EthashGPUMiner: public GenericMiner, Worker { friend class dev::eth::EthashCLHook; @@ -234,66 +258,84 @@ private: }; #endif -class EthashSeal: public SealFace +struct EthashSealEngine: public SealEngineBase { -public: - EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} - - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - Ethash::BlockHeader h(_bi); - h.m_mixHash = m_mixHash; - h.m_nonce = m_nonce; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } - -private: - h256 m_mixHash; - h64 m_nonce; -}; + friend class Ethash; -struct EthashSealEngine: public SealEngineFace -{ public: EthashSealEngine() { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; #if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; #endif m_farm.setSealers(sealers); } - strings sealers() const override { return { "cpu", "opencl" }; } + strings sealers() const override + { + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; + } void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void disable() override { m_farm.stop(); } + void cancelGeneration() override { m_farm.stop(); } void generateSeal(BlockInfo const& _bi) override { - m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); m_farm.start(m_sealer); - m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + m_farm.setWork(m_sealing); // TODO: take out one before or one after... Ethash::ensurePrecomputed((unsigned)_bi.number); } - void onSealGenerated(std::function const& _f) override + void onSealGenerated(std::function const& _f) override { - m_farm.onSolutionFound([=](Ethash::Solution const& sol) + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) { cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - EthashSeal s(sol.mixHash, sol.nonce); - _f(&s); + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); return true; }); } private: bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; }; +void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + // Go via the farm since the handler function object is stored as a local within the Farm's lambda. + // Has the side effect of stopping local workers, which is good, as long as it only does it for + // valid submissions. + static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); +} + +bool Ethash::isWorking(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.isMining(); + return false; +} + +WorkingProgress Ethash::workingProgress(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.miningProgress(); + return WorkingProgress(); +} + SealEngineFace* Ethash::createSealEngine() { return new EthashSealEngine; @@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE -using UniqueGuard = std::unique_lock; - -template -class Notified -{ -public: - Notified() {} - Notified(N const& _v): m_value(_v) {} - Notified(Notified const&) = delete; - Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - - operator N() const { UniqueGuard l(m_mutex); return m_value; } - - void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } - -private: - mutable Mutex m_mutex; - mutable std::condition_variable m_cv; - N m_value; -}; - class EthashCLHook: public ethash_cl_miner::search_hook { public: diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99baa8a05..576621bd4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -53,59 +53,42 @@ public: static unsigned revision(); static SealEngineFace* createSealEngine(); - // TODO: remove or virtualize - struct Solution - { - h64 nonce; - h256 mixHash; - }; - // TODO: make private - struct Result - { - h256 value; - h256 mixHash; - }; - // TODO: virtualise - struct WorkPackage - { - WorkPackage() = default; - - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } + using Nonce = h64; - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; - }; - static const WorkPackage NullWorkPackage; + static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce); + static bool isWorking(SealEngineFace* _engine); + static WorkingProgress workingProgress(SealEngineFace* _engine); class BlockHeaderRaw: public BlockInfo { - friend class EthashSeal; + friend class EthashSealEngine; public: + static const unsigned SealFields = 2; + bool verify() const; bool preVerify() const; void prep(std::function const& _f = std::function()) const; - WorkPackage package() const; h256 const& seedHash() const; - h64 const& nonce() const { return m_nonce; } + Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 2; - void populateFromHeader(RLP const& _header, Strictness _s); - void clear() { m_mixHash = h256(); m_nonce = h64(); } + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); + void clear() { m_mixHash = h256(); m_nonce = Nonce(); } void noteDirty() const { m_seedHash = h256(); } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - h64 m_nonce; + Nonce m_nonce; h256 m_mixHash; mutable h256 m_seedHash; @@ -115,13 +98,6 @@ public: // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); - - /// Default value of the local work size. Also known as workgroup size. - static const unsigned defaultLocalWorkSize; - /// Default value of the global work size as a multiplier of the local work size - static const unsigned defaultGlobalWorkSizeMultiplier; - /// Default value of the milliseconds per global work size (per batch) - static const unsigned defaultMSPerBatch; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 00537c21a..c511978db 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; } EthashAux* dev::eth::EthashAux::s_this = nullptr; +const unsigned EthashProofOfWork::defaultLocalWorkSize = 64; +const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE +const unsigned EthashProofOfWork::defaultMSPerBatch = 0; +const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage(); + EthashAux::~EthashAux() { } @@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; } -Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) if (FullType dag = get()->m_fulls[_seedHash].lock()) return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { - return Ethash::Result{ ~h256(), h256() }; + return EthashProofOfWork::Result{ ~h256(), h256() }; } } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 132b9b436..d42e46d91 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -34,6 +34,47 @@ namespace eth struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; +/// Proof of work definition for Ethash. +struct EthashProofOfWork +{ + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + WorkPackage() = default; + WorkPackage(Ethash::BlockHeader const& _bh): + boundary(_bh.boundary()), + headerHash(_bh.hashWithout()), + seedHash(_bh.seedHash()) + {} + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; +}; + class EthashAux { public: @@ -46,7 +87,7 @@ public: LightAllocation(h256 const& _seedHash); ~LightAllocation(); bytesConstRef data() const; - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; ethash_light_t light; uint64_t size; }; @@ -55,7 +96,7 @@ public: { FullAllocation(ethash_light_t _light, ethash_callback_t _cb); ~FullAllocation(); - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; bytesConstRef data() const; uint64_t size() const { return ethash_full_dag_size(full); } ethash_full_t full; @@ -79,7 +120,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: EthashAux() {} diff --git a/libethcore/Farm.h b/libethcore/Farm.h index b69f8325a..c86b4804e 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -123,9 +123,9 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const + WorkingProgress const& miningProgress() const { - MiningProgress p; + WorkingProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); @@ -195,7 +195,7 @@ private: std::atomic m_isMining = {false}; mutable SharedMutex x_progress; - mutable MiningProgress m_progress; + mutable WorkingProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 03eba9880..90a5902c4 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,9 +36,9 @@ namespace dev namespace eth { -struct MineInfo: public MiningProgress {}; +struct MineInfo: public WorkingProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) +inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p) { _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp deleted file mode 100644 index 843db72c7..000000000 --- a/libethcore/ProofOfWork.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - 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 ProofOfWork.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "ProofOfWork.h" -#include "BlockInfo.h" -using namespace std; -using namespace dev; -using namespace eth; - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h deleted file mode 100644 index f55c54df6..000000000 --- a/libethcore/ProofOfWork.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 ProofOfWork.h - * @author Gav Wood - * @date 2014 - * - * Determines the PoW algorithm. - */ - -#pragma once - -#include -#include -#include "Common.h" -//#include "Ethash.h" -#include "BasicAuthority.h" - -namespace dev -{ -namespace eth -{ - -using ProofOfWork = BasicAuthority; - -} -} diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index 28381444e..137659dfc 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -25,6 +25,7 @@ #include #include +#include #include "Common.h" namespace dev @@ -34,28 +35,22 @@ namespace eth class BlockInfo; -class SealFace -{ -public: - virtual bool wouldSealHeader(BlockInfo const&) const { return true; } - virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; -}; - class SealEngineFace { public: + virtual std::string name() const = 0; + virtual unsigned revision() const = 0; + virtual unsigned sealFields() const = 0; + virtual bytes sealRLP() const = 0; + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; - virtual void onSealGenerated(std::function const& _f) = 0; - virtual void disable() {} - - // TODO: rename & generalise - virtual bool isMining() const { return false; } - virtual MiningProgress miningProgress() const { return MiningProgress(); } + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} protected: virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } @@ -66,5 +61,15 @@ private: std::unordered_map m_options; }; +template +class SealEngineBase: public SealEngineFace +{ +public: + std::string name() const override { return Sealer::name(); } + unsigned revision() const override { return Sealer::revision(); } + unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; } + bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); } +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 14b13b90d..aae8cbd10 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,12 +35,12 @@ #include #include #include -#include #include #include #include #include "GenesisInfo.h" #include "State.h" +#include "Utility.h" #include "Defaults.h" using namespace std; @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 1 +#define ETH_CATCH 0 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 @@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): + m_genesisState(_genesisState) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit // Initialise with the genesis as the last block on the longest chain. m_genesisBlock = _genesisBlock; m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); + m_genesisState = _genesisState; + + // remove the next line real soon. we don't need to be supporting this forever. + upgradeDatabase(_path, genesisHash()); if (open(_path, _we) != c_minorProtocolVersion) rebuild(_path, _p); @@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); - BlockInfo bi(b); + BlockInfo bi(&b); if (_prepPoW) - Ethash::prep(bi); + Ethash::ensurePrecomputed((unsigned)bi.number); if (bi.parentHash != lastHash) { @@ -351,7 +356,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; @@ -388,7 +393,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad, _ir); + block = verifyBlock(&_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) @@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& auto parentBlock = block(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; - clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); + clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); @@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(_block, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this); for (unsigned i = 0; i < s.pending().size(); ++i) { @@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db) try { cout << "block..." << flush; - BlockInfo bi = info(h); - cout << "details..." << flush; - BlockDetails bd = details(h); + BlockInfo bi(block(h)); + cout << "extras..." << flush; + details(h); cout << "state..." << flush; if (_db.exists(bi.stateRoot)) break; @@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +bytes BlockChain::headerData(h256 const& _hash) const { - VerifiedBlockRef res; - try - { - Strictness strictness = Strictness::CheckEverything; - if (~_ir & ImportRequirements::ValidNonce) - strictness = Strictness::IgnoreNonce; + if (_hash == m_genesisHash) + return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes(); - res.info.populate(_block, strictness); - res.info.verifyInternals(&_block); - } - catch (Exception& ex) { - ex << errinfo_phase(1); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; + ReadGuard l(x_blocks); + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + return BlockInfo::extractHeader(&it->second).data().toBytes(); } - RLP r(_block); - unsigned i = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_uncleIndex(i); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; - } - i = 0; - for (RLP const& tr: r[1]) + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + + if (d.empty()) { - bytesConstRef d = tr.data(); - try - { - res.transactions.push_back(Transaction(d, CheckTransaction::Everything)); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_transactionIndex(i); - ex << errinfo_transaction(d.toBytes()); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; + cwarn << "Couldn't find requested block:" << _hash; + return bytes(); } - res.block = bytesConstRef(&_block); - return res; + + noteUsed(_hash); + + WriteGuard l(x_blocks); + m_blocks[_hash].resize(d.size()); + memcpy(m_blocks[_hash].data(), d.data(), d.size()); + + return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes(); } +State BlockChain::genesisState(OverlayDB const& _db) +{ + State ret(_db, BaseState::Empty); + dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? + ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. + ret.m_previousBlock = BlockInfo(&m_genesisBlock); + return ret; +} + + + + + + + + + + + + + + + + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 638c9c3af..50965f2b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,6 +37,7 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" +#include "State.h" namespace std { @@ -86,6 +87,13 @@ enum { }; using ProgressCallback = std::function; +using StateDefinition = std::unordered_map; + +class VersionChecker +{ +public: + VersionChecker(std::string const& _dbPath, h256 const& _genesisHash); +}; /** * @brief Implements the blockchain database. All data this gives is disk-backed. @@ -94,7 +102,7 @@ using ProgressCallback = std::function; class BlockChain { public: - BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); ~BlockChain(); /// Attempt a database re-open. @@ -120,14 +128,17 @@ public: /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; - /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. - BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); } + /// Get the partial-header of a block (or the most recent mined if none given). Thread-safe. + BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); } BlockInfo info() const { return info(currentHash()); } /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. bytes block(h256 const& _hash) const; bytes block() const { return block(currentHash()); } - bytes oldBlock(h256 const& _hash) const; + + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes headerData(h256 const& _hash) const; + bytes headerData() const { return headerData(currentHash()); } /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. BlockDetails details(h256 const& _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } @@ -264,13 +275,16 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); - /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); - /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } -private: + /// Get a pre-made genesis State object. + State genesisState(OverlayDB const& _db); + + /// Verify block and prepare it for enactment + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + +protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); @@ -345,6 +359,7 @@ private: /// Genesis block info. h256 m_genesisHash; bytes m_genesisBlock; + std::unordered_map m_genesisState; ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; @@ -354,6 +369,88 @@ private: friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; +template +class FullBlockChain: public BlockChain +{ +public: + using BlockHeader = typename Sealer::BlockHeader; + + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path, _we, _p) + {} + + /// Get the header of a block (or the most recent mined if none given). Thread-safe. + typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } + typename Sealer::BlockHeader header() const { return header(currentHash()); } + + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + { + VerifiedBlockRef res; + + try + { + BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); + h.verifyInternals(_block); + h.verifyParent(header(h.parentHash)); + res.info = static_cast(h); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + if (_ir && ImportRequirements::UncleBasic) + for (auto const& uncle: r[2]) + { + try + { + BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + if (_ir && ImportRequirements::TransactionBasic) + for (RLP const& tr: r[1]) + { + bytesConstRef d = tr.data(); + try + { + res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None)); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_transactionIndex(i); + ex << errinfo_transaction(d.toBytes()); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + res.block = bytesConstRef(_block); + return res; + } +}; + std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); } diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 2cf2a7583..a59326b77 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const for (unsigned i = 0; i < itemCount; ++i) { - auto h = BlockInfo::headerHash(_r[i].data()); + auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) + switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; @@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const logNewBlock(h); if (m_state == SyncState::NewBlocks) { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); + BlockInfo bi(_r[i].data()); if (bi.number > maxUnknownNumber) { maxUnknownNumber = bi.number; @@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP con { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); + auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { - switch (host().bq().import(_r[0].data(), host().chain())) + switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b6c548c1f..6b400b236 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); } catch (...) { @@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() } } -ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) +ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. - h256 h = BlockInfo::headerHash(_block); + h256 h = BlockInfo::headerHashFromBlock(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; @@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::AlreadyKnown; } - // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { - // TODO: quick verify - bi.populate(_block); - bi.verifyInternals(_block); + // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer + // VERIFY: populates from the block and checks the block is internally coherent. + bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info; } catch (Exception const& _e) { @@ -218,7 +216,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! - if (_bc.isKnown(h)) + if (m_bc->isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; @@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else @@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; @@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad) return !m_readySet.empty(); } -void BlockQueue::tick(BlockChain const& _bc) +void BlockQueue::tick() { vector> todo; { @@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc) cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) - import(&b.second, _bc); + import(&b.second); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index b9e6f5b3b..97fca7c72 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -76,11 +76,13 @@ public: BlockQueue(); ~BlockQueue(); + void setChain(BlockChain const& _bc) { m_bc = &_bc; } + /// Import a block into the queue. - ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. - void tick(BlockChain const& _bc); + void tick(); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. @@ -138,6 +140,8 @@ private: void updateBad_WITH_LOCK(h256 const& _bad); void drainVerified_WITH_BOTH_LOCKS(); + BlockChain const* m_bc; ///< The blockchain into which our imports go. + mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. h256Hash m_readySet; ///< All blocks ready for chain import. diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 4e6d89243..eee4b98b7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -41,14 +40,44 @@ namespace js = json_spirit; #define ETH_CATCH 1 -std::unordered_map const& dev::eth::genesisState() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); +std::string CanonBlockChain::s_genesisStateJSON; + +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) +{ +} + +bytes CanonBlockChain::createGenesisBlock() +{ + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + SecureTrieDB state(&db); + state.init(); + dev::eth::commit(createGenesisState(), state); + stateRoot = state.root(); + } + + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +unordered_map CanonBlockChain::createGenesisState() { static std::unordered_map s_ret; if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(c_genesisInfo, val); + json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()) { u256 balance; @@ -68,53 +97,29 @@ std::unordered_map const& dev::eth::genesisState() return s_ret; } -// TODO: place Registry in here. - -std::unique_ptr CanonBlockChain::s_genesis; -boost::shared_mutex CanonBlockChain::x_genesis; -Nonce CanonBlockChain::s_nonce(u64(42)); - -bytes CanonBlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - SecureTrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - BlockChain(createGenesisBlock(), _path, _we, _pc) +void CanonBlockChain::setGenesisState(std::string const& _json) { + WriteGuard l(x_genesis); + s_genesisStateJSON = _json; + s_genesis.reset(); } -void CanonBlockChain::setGenesisNonce(Nonce const& _n) +void CanonBlockChain::setGenesisNonce(Nonce const& _n) { WriteGuard l(x_genesis); s_nonce = _n; s_genesis.reset(); } -BlockInfo const& CanonBlockChain::genesis() +Ethash::BlockHeader const& CanonBlockChain::genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); - s_genesis.reset(new BlockInfo); - s_genesis->populate(&gb); + s_genesis.reset(new Ethash::BlockHeader); + s_genesis->populate(&gb, CheckEverything); } return *s_genesis; } diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index c16479f0d..d79926703 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BlockDetails.h" #include "Account.h" @@ -45,7 +46,32 @@ std::unordered_map const& genesisState(); * @threadsafe * @todo Make not memory hog (should actually act as a cache and deallocate old entries). */ -class CanonBlockChain: public BlockChain +template +class CanonBlockChain: public FullBlockChain +{ +public: + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + ~CanonBlockChain() {} + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock() + { + RLPStream block(3); + block.appendList(Sealer::BlockHeader::Fields) + << h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string(); + bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP(); + block.appendRaw(sealFields, Sealer::BlockHeader::SealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); + } +}; + +template <> +class CanonBlockChain: public FullBlockChain { public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} @@ -53,22 +79,35 @@ public: ~CanonBlockChain() {} /// @returns the genesis block header. - static BlockInfo const& genesis(); + static Ethash::BlockHeader const& genesis(); /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static std::unordered_map createGenesisState(); + /// Alter the value of the genesis block's nonce. /// @warning Unless you're very careful, make sure you call this right at the start of the /// program, before anything has had the chance to use this class at all. static void setGenesisNonce(Nonce const& _n); + /// Alter all the genesis block's state by giving a JSON string with account details. + /// @TODO implement. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisState(std::string const&); + + // TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, + private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + static std::unique_ptr s_genesis; static Nonce s_nonce; + static std::string s_genesisStateJSON; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 918480263..ec37302a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -72,47 +72,43 @@ static const Addresses c_canaries = Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph }; -VersionChecker::VersionChecker(string const& _dbPath) +Client::Client(std::shared_ptr _gp): + Worker("eth", 0), + m_gp(_gp ? _gp : make_shared()) { - upgradeDatabase(_dbPath); } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Client(_extNet, make_shared(), _dbPath, _forceAction, _networkId) +void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId) { - startWorking(); -} + // Cannot be opened until after blockchain is open, since BlockChain may upgrade the database. + // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database + // until after the construction. + m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); + m_preMine = State(m_stateDB); + m_postMine = State(m_stateDB); + // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. + m_preMine = bc().genesisState(m_stateDB); -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth", 0), - m_vc(_dbPath), - m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), - m_gp(_gp), - m_stateDB(State::openDB(_dbPath, _forceAction)), - m_preMine(m_stateDB, BaseState::CanonGenesis), - m_postMine(m_stateDB) -{ - if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + m_bq.setChain(bc()); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_sealEngine = shared_ptr(Ethash::createSealEngine()); - m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); + bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_gp->update(m_bc); + if (_forceAction == WithExisting::Rescue) + m_bc.rescue(m_stateDB); + + m_gp->update(bc()); - auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); + auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId)); m_host = host; _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common if (_dbPath.size()) Defaults::setDBPath(_dbPath); doWork(); - startWorking(); } @@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000) this_thread::sleep_for(std::chrono::milliseconds(500)); - return m_bq.import(&_block, bc(), _isSafe); + return m_bq.import(&_block, _isSafe); } tuple Client::syncQueue(unsigned _max) { stopWorking(); - return m_bc.sync(m_bq, m_stateDB, _max); + return bc().sync(m_bq, m_stateDB, _max); } void Client::onBadBlock(Exception& _ex) const @@ -294,7 +290,7 @@ void Client::startedWorking() clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -309,7 +305,7 @@ void Client::doneWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -328,7 +324,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.disable(); + m_sealEngine->cancelGeneration(); { WriteGuard l(x_postMine); @@ -340,10 +336,10 @@ void Client::killChain() m_working = State(); m_stateDB = OverlayDB(); - m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); - m_bc.reopen(Defaults::dbPath(), WithExisting::Kill); + m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); + bc().reopen(Defaults::dbPath(), WithExisting::Kill); - m_preMine = State(m_stateDB, BaseState::CanonGenesis); + m_preMine = bc().genesisState(m_stateDB); m_postMine = State(m_stateDB); } @@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); - auto receipts = m_bc.receipts(_block).receipts; + auto d = bc().info(_block); + auto receipts = bc().receipts(_block).receipts; Guard l(x_filtersWatches); io_changed.insert(ChainChangedFilter); @@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable) startMining(); } -MiningProgress Client::miningProgress() const +bool Client::isMining() const { - if (m_farm.isMining()) - return m_farm.miningProgress(); - return MiningProgress(); + return Ethash::isWorking(m_sealEngine.get()); +} + +WorkingProgress Client::miningProgress() const +{ + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()); + return WorkingProgress(); } uint64_t Client::hashrate() const { - if (m_farm.isMining()) - return m_farm.miningProgress().rate(); + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()).rate(); return 0; } @@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -ProofOfWork::WorkPackage Client::getWork() -{ - // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. - // this will be reset as soon as a new block arrives, allowing more transactions to be processed. - bool oldShould = shouldServeWork(); - m_lastGetWork = chrono::system_clock::now(); - - if (!m_mineOnBadChain && isChainBad()) - return ProofOfWork::WorkPackage(); - - // if this request has made us bother to serve work, prep it now. - if (!oldShould && shouldServeWork()) - onPostStateChanged(); - else - // otherwise, set this to true so that it gets prepped next time. - m_remoteWorking = true; - return ProofOfWork::package(m_miningInfo); -} - -bool Client::submitWork(ProofOfWork::Solution const& _solution) -{ - bytes newBlock; - DEV_WRITE_GUARDED(x_working) - if (!m_working.completeMine(_solution)) - return false; - - DEV_READ_GUARDED(x_working) - { - DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; - newBlock = m_working.blockData(); - } - - // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. - m_bq.import(&newBlock, m_bc, true); - - return true; -} - unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; @@ -553,7 +515,7 @@ void Client::syncBlockQueue() ImportRoute ir; unsigned count; Timer t; - tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); if (count) @@ -577,7 +539,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; DEV_WRITE_GUARDED(x_working) - tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp); if (newPendingReceipts.empty()) return; @@ -590,7 +552,7 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restart mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& h: _ir.deadBlocks) { clog(ClientTrace) << "Dead block:" << h; - for (auto const& t: m_bc.transactions(h)) + for (auto const& t: bc().transactions(h)) { clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, IfDropped::Retry); @@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir) newPreMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + preChanged = newPreMine.sync(bc()); if (preChanged || m_postMine.address() != m_preMine.address()) { @@ -700,7 +662,7 @@ void Client::rejigMining() { clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) - m_working.commitToMine(m_bc, m_extraData); + m_working.commitToMine(bc(), m_extraData); DEV_READ_GUARDED(x_working) { DEV_WRITE_GUARDED(x_postMine) @@ -709,10 +671,10 @@ void Client::rejigMining() } if (m_wouldMine) - m_farm.sealBlock(m_miningInfo); + m_sealEngine->generateSeal(m_miningInfo); } if (!m_wouldMine) - m_farm.disable(); + m_sealEngine->cancelGeneration(); } void Client::noteChanged(h256Hash const& _filters) @@ -768,7 +730,7 @@ void Client::tick() { m_report.ticks++; checkWatchGarbage(); - m_bq.tick(m_bc); + m_bq.tick(); m_lastTick = chrono::system_clock::now(); if (m_report.ticks == 15) clog(ClientTrace) << activityReport(); @@ -792,7 +754,7 @@ void Client::checkWatchGarbage() uninstallWatch(i); // blockchain GC - m_bc.garbageCollect(); + bc().garbageCollect(); m_lastGarbageCollection = chrono::system_clock::now(); } @@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const try { State ret(m_stateDB); - ret.populateFromChain(m_bc, _block); + ret.populateFromChain(bc(), _block); return ret.fromPending(_txi); } catch (Exception& ex) @@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const try { State ret(m_stateDB); - PopulationStatistics s = ret.populateFromChain(m_bc, _block); + PopulationStatistics s = ret.populateFromChain(bc(), _block); if (o_stats) swap(s, *o_stats); return ret; @@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const auto h = m_host.lock(); return h ? h->status() : SyncStatus(); } + +bool Client::submitSealed(bytes const& _header) +{ + DEV_WRITE_GUARDED(x_working) + if (!m_working.sealBlock(_header)) + return false; + + bytes newBlock; + DEV_READ_GUARDED(x_working) + { + DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + newBlock = m_working.blockData(); + } + + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. + return m_bq.import(&newBlock, true) == ImportResult::Success; +} + + + + + + + + + + + + + + +std::tuple EthashClient::getEthashWork() +{ + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); + m_lastGetWork = chrono::system_clock::now(); + + if (!m_mineOnBadChain && isChainBad()) + return std::tuple(); + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; + Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + return std::tuple(bh.boundary(), bh.hashWithout(), bh.seedHash()); +} + +bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce) +{ + Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce); + return true; +} + diff --git a/libethereum/Client.h b/libethereum/Client.h index 9ae7c7e09..73609bd71 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -60,12 +60,6 @@ enum ClientWorkState Deleted }; -class VersionChecker -{ -public: - VersionChecker(std::string const& _dbPath); -}; - struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; @@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); /** * @brief Main API hub for interfacing with Ethereum. + * Not to be used directly - subclass. */ class Client: public ClientBase, Worker { public: /// New-style Constructor. - explicit Client( - p2p::Host* _host, - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); - - explicit Client( - p2p::Host* _host, - std::shared_ptr _gpForAdoption, // pass it in with new. - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); + /// Any final derived class's constructor should make sure they call init(). + explicit Client(std::shared_ptr _gpForAdoption); /// Destructor. virtual ~Client(); @@ -129,7 +112,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. - CanonBlockChain const& blockChain() const { return m_bc; } + BlockChain const& blockChain() const { return bc(); } /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. @@ -176,26 +159,16 @@ public: /// NOT thread-safe void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? - bool isMining() const override { return m_farm.isMining(); } + bool isMining() const override; /// Are we mining now? bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MiningProgress miningProgress() const override; + WorkingProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); - /// Update to the latest transactions and get hash of the current block to be mined minus the - /// nonce (the 'work hash') and the difficulty to be met. - virtual ProofOfWork::WorkPackage getWork() override; - - /** @brief Submit the proof for the proof-of-work. - * @param _s A valid solution. - * @return true if the solution was indeed valid and accepted. - */ - virtual bool submitWork(ProofOfWork::Solution const& _proof) override; - // Debug stuff: DownloadMan const* downloadMan() const; @@ -218,12 +191,20 @@ public: /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } /// Rewind to a prior head. - void rewind(unsigned _n) { m_bc.rewind(_n); } + void rewind(unsigned _n) { bc().rewind(_n); } + /// Rescue the chain. + void rescue() { bc().rescue(m_stateDB); } + /// Get the seal engine. + SealEngineFace* sealEngine() const { return m_sealEngine.get(); } protected: + /// Perform critical setup functions. + /// Must be called in the constructor of the finally derived class. + void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); + /// InterfaceStub methods - virtual BlockChain& bc() override { return m_bc; } - virtual BlockChain const& bc() const override { return m_bc; } + virtual BlockChain& bc() override = 0; + virtual BlockChain const& bc() const override = 0; /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. @@ -245,7 +226,10 @@ protected: /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. void noteChanged(h256Hash const& _filters); -private: + /// Submit + bool submitSealed(bytes const& _s); + +protected: /// Called when Worker is starting. void startedWorking() override; @@ -291,8 +275,6 @@ private: /// @warning May be called from any thread. void onBadBlock(Exception& _ex) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -339,5 +321,64 @@ private: bytes m_extraData; }; +template +class SpecialisedClient: public Client +{ +public: + explicit SpecialisedClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): + Client(_gpForAdoption), + m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }) + { + m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSealGenerated([=](bytes const& header){ + return this->submitSealed(header); + }); + init(_host, _dbPath, _forceAction, _networkId); + } + + /// Get the object representing the current canonical blockchain. + CanonBlockChain const& blockChain() const { return m_bc; } + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } + +protected: + CanonBlockChain m_bc; ///< Maintains block database. +}; + +class EthashClient: public SpecialisedClient +{ +public: + /// Trivial forwarding constructor. + explicit EthashClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + + /// Update to the latest transactions and get hash of the current block to be mined minus the + /// nonce (the 'work hash') and the difficulty to be met. + virtual std::tuple getEthashWork() override; + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ + virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } +}; + } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f463b0195..769880269 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const auto bl = bc().block(_blockHash); RLP b(bl); if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); + return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData); else return BlockInfo(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 82f03def0..874f10548 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -156,9 +156,7 @@ public: virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } - virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } - virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } - virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } + virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 973433af9..213e7fb26 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" @@ -207,12 +207,12 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual ProofOfWork::WorkPackage getWork() = 0; + virtual std::tuple getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); } /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; + virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); } /// Check the progress of the mining. - virtual MiningProgress miningProgress() const = 0; + virtual WorkingProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1656109a9..ee2078a07 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } -OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) +OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; @@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) boost::filesystem::remove_all(path + "/state"); } - path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); + path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); ldb::Options o; @@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("beginning of Genesis construction.", true); - if (_bs == BaseState::CanonGenesis) - { - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); - - paranoia("after DB commit of Genesis construction.", true); - m_previousBlock = CanonBlockChain::genesis(); - } - else - m_previousBlock.clear(); - - resetCurrent(); - - assert(m_state.root() == m_previousBlock.stateRoot); + m_previousBlock.clear(); + m_currentBlock.clear(); +// assert(m_state.root() == m_previousBlock.stateRoot); paranoia("end of normal construction.", true); } @@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip; - bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip, _ir); + BlockInfo bip(_bc.block(bi.parentHash)); + sync(_bc, bi.parentHash, bip); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; - auto vb = BlockChain::verifyBlock(b); + auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); t.restart(); - enact(vb, _bc, _ir); + enact(vb, _bc); ret.enact = t.elapsed(); } else @@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi, _ir); + sync(_bc, _h, bi); } return ret; @@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ void State::commit() { - m_touched += dev::eth::commit(m_cache, m_db, m_state); + m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } @@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) +bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi) { - (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -355,7 +342,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor { cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; - cwarn << "Bailing."; + cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); } m_previousBlock = bi; @@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) { #if ETH_TIMED_ENACTMENTS Timer t; @@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _ir); + auto ret = enact(_block, _bc); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire RLP rlp(_block); cleanup(false); - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal); m_currentBlock = bi; m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); @@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) { DEV_TIMED_FUNCTION_ABOVE(500); @@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = _block.info; m_currentBlock.noteDirty(); + m_currentBlock = _block.info; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } @@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + // IgnoreSeal since it's a VerifiedBlock. + BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; if (!_bc.isKnown(uncle.parentHash)) @@ -829,6 +817,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { + (void)_bc; + /* commitToMine(_bc); // Update difficulty according to timestamp. @@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out(), std::function(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) { cwarn << "Bad block: " << _e.what(); } - +*/ return false; } @@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) for (auto const& u: us) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { - BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithProof); + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); ++unclesCount; - uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) break; } @@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) m_committedToMine = true; } -void State::completeMine() +bool State::sealBlock(bytesConstRef _header) { - cdebug << "Completing mine!"; + if (!m_committedToMine) + return false; + + cdebug << "Sealing block!"; // Got it! // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithProof); + ret.appendRaw(_header); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); - m_currentBlock.noteDirty(); + m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; -/* StructuredLogger::minedNewBlock( + // TODO: move into Sealer + StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.proof.nonce.abridged(), + "", // Can't give the nonce here. "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - );*/ + ); // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. @@ -989,6 +982,8 @@ void State::completeMine() m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; + + return true; } bool State::addressInUse(Address _id) const diff --git a/libethereum/State.h b/libethereum/State.h index f6a8471ea..805215ee5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "Account.h" @@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati enum class BaseState { PreExisting, - Empty, - CanonGenesis + Empty }; enum class Permanence @@ -104,6 +102,7 @@ class State friend class dev::test::ImportTest; friend class dev::test::StateLoader; friend class Executive; + friend class BlockChain; public: /// Default constructor; creates with a blank database prepopulated with the genesis block. @@ -125,7 +124,7 @@ public: ~State(); /// Construct state object from arbitrary point in blockchain. - PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None); /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. @@ -133,8 +132,8 @@ public: Address address() const { return m_ourAddress; } /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. - static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust); - static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } + static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); } OverlayDB const& db() const { return m_db; } OverlayDB& db() { return m_db; } @@ -163,22 +162,20 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. - template - bool completeMine(typename PoW::Solution const& _result) - { - if (!m_committedToMine) - return false; - - m_currentBlock.proof = _result; - if (!PoW::verify(m_currentBlock)) - return false; - -// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - - completeMine(); - - return true; - } + /// TODO: verify it prior to calling this. + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * while (notYetMined) + * { + * // lock + * commitToMine(_blockChain); // will call uncommitToMine if a repeat. + * completeMine(); + * // unlock + * @endcode + */ + bool sealBlock(bytes const& _header) { return sealBlock(&_header); } + bool sealBlock(bytesConstRef _header); /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. @@ -295,11 +292,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); + bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -313,19 +310,6 @@ public: void resetCurrent(); private: - /** Commit to DB and build the final block if the previous call to mine()'s result is completion. - * Typically looks like: - * @code - * while (notYetMined) - * { - * // lock - * commitToMine(_blockChain); // will call uncommitToMine if a repeat. - * completeMine(); - * // unlock - * @endcode - */ - void completeMine(); - /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -340,7 +324,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -386,7 +370,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, SecureTrieDB& _state) { AddressHash ret; for (auto const& i: _cache) @@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, } else { - SecureTrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); @@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, if (i.second.isFreshCode()) { h256 ch = sha3(i.second.code()); - _db.insert(ch, &i.second.code()); + _state.db()->insert(ch, &i.second.code()); s << ch; } else diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index e02012cd5..1b97f82e7 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args) return m_data; } -void dev::eth::upgradeDatabase(std::string const& _basePath) +void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash) { std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath; @@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath) { auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; - auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash; string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(databaseVersion); diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 0dfe8509b..df48269ec 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -42,7 +43,7 @@ namespace eth */ bytes parseData(std::string const& _args); -void upgradeDatabase(std::string const& _basePath); +void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash); } } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 7d63ed165..15d39bded 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); -#if ETH_USING_ETHASH // TODO: move into ProofOfWork. - res["nonce"] = toJS(_bi.proof.nonce); - res["seedHash"] = toJS(_bi.proofCache()); -#endif +// res["nonce"] = toJS(_bi.proof.nonce); +// res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..624a73e54 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. +template +Json::Value toJson(BlockHeaderPolished const& _bh) +{ + Json::Value res; + if (_bh) + { + res = toJson(static_cast(_bh)); + for (auto const& i: _bh.jsInfo()) + res[i.first] = i.second; + } + return res; +} + } namespace shh diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 1743882e5..061b5ae79 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -24,7 +24,6 @@ #include #include "../JsonSpiritHeaders.h" #include -#include #include #include #include "../TestHelper.h" @@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - Ethash::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 452163061..e3f8ac29f 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. From e14d000bea7b231f7947a5f009dc53201de83a84 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:29:03 +0200 Subject: [PATCH 092/113] All fields of BlockInfo now private. --- alethzero/MainWin.cpp | 34 +++--- ethminer/MinerAux.h | 4 +- evmjit/libevmjit-cpp/JitVM.cpp | 6 +- evmjit/libevmjit/RuntimeManager.cpp | 6 +- exp/main.cpp | 6 +- libethcore/BasicAuthority.cpp | 8 +- libethcore/BlockInfo.cpp | 104 ++++++++--------- libethcore/BlockInfo.h | 91 +++++++++------ libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 40 +++---- libethcore/EthashAux.cpp | 2 +- libethereum/BasicGasPricer.cpp | 6 +- libethereum/BlockChain.cpp | 78 +++++-------- libethereum/BlockChain.h | 2 +- libethereum/BlockChainSync.cpp | 6 +- libethereum/BlockQueue.cpp | 50 ++++---- libethereum/Executive.cpp | 10 +- libethereum/State.cpp | 133 +++++++++++----------- libethereum/State.h | 2 +- libevm/ExtVMFace.h | 4 +- libevm/VM.cpp | 10 +- libtestutils/BlockChainLoader.cpp | 2 +- libweb3jsonrpc/JsonHelper.cpp | 22 ++-- test/TestHelper.cpp | 6 +- test/libethereum/ClientBase.cpp | 18 +-- test/libethereum/blockchain.cpp | 78 ++++++------- test/libethereum/genesis.cpp | 2 +- test/libevm/vm.cpp | 12 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- third/MainWin.cpp | 2 +- 30 files changed, 378 insertions(+), 370 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2ee8928f5..ad8f5528c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,7 +189,7 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; @@ -1629,7 +1629,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1706,7 +1706,7 @@ void Main::on_blocks_currentItemChanged() if (item->data(Qt::UserRole + 1).isNull()) { char timestamp[64]; - time_t rawTime = (time_t)(uint64_t)info.timestamp; + time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; s << "

#" << info.number; @@ -1714,7 +1714,7 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; - s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "" << "
"; + s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; @@ -1724,7 +1724,7 @@ void Main::on_blocks_currentItemChanged() { auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; - s << "
Parent: " << info.parentHash << "" << "
"; + s << "
Parent: " << info.parentHash() << "" << "
"; } else { @@ -1732,20 +1732,20 @@ void Main::on_blocks_currentItemChanged() s << "
Parent: It was a virgin birth
"; } // s << "
Bloom: " << details.bloom << ""; - if (!!info.logBloom) - s << "
Log Bloom: " << info.logBloom << "
"; + if (!!info.logBloom()) + s << "
Log Bloom: " << info.logBloom() << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; - s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Parent: " << uncle.parentHash() << "" << ""; s << line << "Number: " << uncle.number << "" << ""; - s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; @@ -1754,20 +1754,20 @@ void Main::on_blocks_currentItemChanged() auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } - if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; + if (info.parentHash()) + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; else s << "
Pre: Nothing is before Phil" << "
"; - s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; + s << "
Receipts: @" << info.receiptsRoot() << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Post: " << info.stateRoot() << "" << "
"; s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } @@ -1807,7 +1807,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 61fde605d..0d227b1ef 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -398,8 +398,8 @@ private: void doInitDAG(unsigned _n) { BlockInfo bi; - bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; + bi.number() = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 2fb2a0e67..4e1fb66ea 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -24,7 +24,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index d48b64bb1..b2c15d7ae 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,7 +1,7 @@ #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" #include "Stack.h" @@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; + case RuntimeData::Timestamp: return "block.timestamp()"; case RuntimeData::Code: return "code.ptr"; case RuntimeData::CodeSize: return "code.size"; } diff --git a/exp/main.cpp b/exp/main.cpp index 4a35068f1..0b740e526 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,8 +85,8 @@ int main() BlockInfo bi; bi.difficulty = c_genesisDifficulty; bi.gasLimit = c_genesisGasLimit; - bi.number = 1; - bi.parentHash = sha3("parentHash"); + bi.number() = 1; + bi.parentHash() = sha3("parentHash"); bytes sealedData; @@ -329,7 +329,7 @@ int main() mine(s, bc, se); bytes minedBlock = s.blockData(); - cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot(); bc.import(minedBlock, stateDB); cnote << bc; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 22da67080..7ef3dd21e 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -44,19 +44,19 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri m_sig = _header[BlockInfo::BasicFields].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); BOOST_THROW_EXCEPTION(ex); } } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 64961bc40..266f57cc8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -BlockInfo::BlockInfo(): timestamp(Invalid256) +BlockInfo::BlockInfo(): m_timestamp(Invalid256) { } @@ -45,26 +45,26 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, void BlockInfo::clear() { - parentHash = h256(); - sha3Uncles = EmptyListSHA3; - coinbaseAddress = Address(); - stateRoot = EmptyTrie; - transactionsRoot = EmptyTrie; - receiptsRoot = EmptyTrie; - logBloom = LogBloom(); - difficulty = 0; - number = 0; - gasLimit = 0; - gasUsed = 0; - timestamp = 0; - extraData.clear(); + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_coinbaseAddress = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = 0; + m_extraData.clear(); noteDirty(); } h256 const& BlockInfo::boundary() const { - if (!m_boundary && difficulty) - m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); + if (!m_boundary && m_difficulty) + m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty); return m_boundary; } @@ -81,8 +81,8 @@ h256 const& BlockInfo::hashWithout() const void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << gasLimit << gasUsed << timestamp << extraData; + _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; } h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) @@ -110,19 +110,19 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { - parentHash = _header[field = 0].toHash(RLP::VeryStrict); - sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); - coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); - stateRoot = _header[field = 3].toHash(RLP::VeryStrict); - transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); - receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); - logBloom = _header[field = 6].toHash(RLP::VeryStrict); - difficulty = _header[field = 7].toInt(); - number = _header[field = 8].toInt(); - gasLimit = _header[field = 9].toInt(); - gasUsed = _header[field = 10].toInt(); - timestamp = _header[field = 11].toInt(); - extraData = _header[field = 12].toBytes(); + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toInt(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toInt(); + m_extraData = _header[field = 12].toBytes(); } catch (Exception const& _e) { @@ -130,11 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) throw; } - if (number > ~(unsigned)0) + if (m_number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing && gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); + if (_s != CheckNothing && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -147,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); - if (transactionsRoot != expectedRoot) + if (m_transactionsRoot != expectedRoot) { MemoryDB tm; GenericTrieDB transactionsTrie(&tm); @@ -172,52 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) cdebug << toHex(t); - BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot)); + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); - if (sha3Uncles != sha3(root[2].data())) + if (m_sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } void BlockInfo::populateFromParent(BlockInfo const& _parent) { - stateRoot = _parent.stateRoot; - number = _parent.number + 1; - gasLimit = selectGasLimit(_parent); - gasUsed = 0; - difficulty = calculateDifficulty(_parent); - parentHash = _parent.hash(); + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_gasLimit = selectGasLimit(_parent); + m_gasUsed = 0; + m_difficulty = calculateDifficulty(_parent); + m_parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return c_genesisGasLimit; else // target minimum of 3141592 - if (_parent.gasLimit < c_genesisGasLimit) - return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + if (_parent.m_gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return (u256)c_genesisDifficulty; else - return max(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor))); + return max(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); } void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check timestamp is after previous timestamp. - if (parentHash) + if (m_parentHash) { - if (timestamp <= _parent.timestamp) + if (m_timestamp <= _parent.m_timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); - if (number != _parent.number + 1) + if (m_number != _parent.m_number + 1) BOOST_THROW_EXCEPTION(InvalidNumber()); } } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b00fa73fb..67a5397f4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -81,21 +81,6 @@ struct BlockInfo public: static const unsigned BasicFields = 13; - // TODO: make them all private! - h256 parentHash; - h256 sha3Uncles; - Address coinbaseAddress; - h256 stateRoot; - h256 transactionsRoot; - h256 receiptsRoot; - LogBloom logBloom; - u256 difficulty; // TODO: pull out into BlockHeader - u256 number; - u256 gasLimit; - u256 gasUsed; - u256 timestamp = Invalid256; - bytes extraData; - BlockInfo(); explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} @@ -104,23 +89,23 @@ public: static h256 headerHashFromBlock(bytesConstRef _block); static RLP extractHeader(bytesConstRef _block); - explicit operator bool() const { return timestamp != Invalid256; } + explicit operator bool() const { return m_timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { - return parentHash == _cmp.parentHash && - sha3Uncles == _cmp.sha3Uncles && - coinbaseAddress == _cmp.coinbaseAddress && - stateRoot == _cmp.stateRoot && - transactionsRoot == _cmp.transactionsRoot && - receiptsRoot == _cmp.receiptsRoot && - logBloom == _cmp.logBloom && - difficulty == _cmp.difficulty && - number == _cmp.number && - gasLimit == _cmp.gasLimit && - gasUsed == _cmp.gasUsed && - timestamp == _cmp.timestamp && - extraData == _cmp.extraData; + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_coinbaseAddress == _cmp.coinbaseAddress() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } @@ -132,6 +117,31 @@ public: u256 selectGasLimit(BlockInfo const& _parent) const; h256 const& boundary() const; + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); } + void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + + Address const& coinbaseAddress() const { return m_coinbaseAddress; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& timestamp() const { return m_timestamp; } + bytes const& extraData() const { return m_extraData; } + + u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader + /// sha3 of the header only. h256 const& hashWithout() const; h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } @@ -145,6 +155,21 @@ protected: mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + h256 m_parentHash; + h256 m_sha3Uncles; + Address m_coinbaseAddress; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + u256 m_number; + u256 m_gasLimit; + u256 m_gasUsed; + u256 m_timestamp = Invalid256; + bytes m_extraData; + + u256 m_difficulty; // TODO: pull out into BlockHeader + private: mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty @@ -152,9 +177,9 @@ private: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp; + _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); return _out; } @@ -191,7 +216,7 @@ public: // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { - if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); BlockInfoSub::verifyParent(_parent); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 499854584..05cc45280 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -124,7 +124,7 @@ static void badBlockInfo(BlockInfo const& _bi, string const& _err) ss << c_space << endl; ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_space << endl; - string bin = toString(_bi.number); + string bin = toString(_bi.number()); ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; ss << c_space << endl; ss << c_line; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 128822b80..ee483aa8b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ namespace eth h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); + m_seedHash = EthashAux::seedHash((unsigned)m_number); return m_seedHash; } @@ -72,7 +72,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_nonce(m_nonce); @@ -81,42 +81,42 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } if (_s != CheckNothing) { - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + if (m_difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) ); - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + if (m_gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) ); - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + if (m_number && m_extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size()))); } } void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) { // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + if (m_difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty)); - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); + if (m_gasLimit < c_minGasLimit || + m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor || + m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)); } void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) @@ -126,7 +126,7 @@ void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) bool Ethash::BlockHeaderRaw::preVerify() const { - if (number >= ETHASH_EPOCH_LENGTH * 2048) + if (m_number >= ETHASH_EPOCH_LENGTH * 2048) return false; bool ret = !!ethash_quick_check_difficulty( @@ -162,7 +162,7 @@ bool Ethash::BlockHeaderRaw::verify() const cwarn << "headerHash:" << hashWithout(); cwarn << "nonce:" << m_nonce; cwarn << "mixHash:" << m_mixHash; - cwarn << "difficulty:" << difficulty; + cwarn << "difficulty:" << m_difficulty; cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; @@ -290,7 +290,7 @@ public: m_farm.setWork(m_sealing); m_farm.start(m_sealer); m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number); + Ethash::ensurePrecomputed((unsigned)_bi.number()); } void onSealGenerated(std::function const& _f) override { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index c511978db..763bea417 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,7 +63,7 @@ EthashAux* EthashAux::get() uint64_t EthashAux::cacheSize(BlockInfo const& _header) { - return ethash_get_cachesize((uint64_t)_header.number); + return ethash_get_cachesize((uint64_t)_header.number()); } uint64_t EthashAux::dataSize(uint64_t _blockNumber) diff --git a/libethereum/BasicGasPricer.cpp b/libethereum/BasicGasPricer.cpp index 145d23594..b957966f8 100644 --- a/libethereum/BasicGasPricer.cpp +++ b/libethereum/BasicGasPricer.cpp @@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; h256 p = _bc.currentHash(); - m_gasPerBlock = _bc.info(p).gasLimit; + m_gasPerBlock = _bc.info(p).gasLimit(); map dist; u256 total = 0; @@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc) while (c < 1000 && p) { BlockInfo bi = _bc.info(p); - if (bi.transactionsRoot != EmptyTrie) + if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); @@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc) i++; } } - p = bi.parentHash; + p = bi.parentHash(); ++c; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aae8cbd10..b696c77bd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) { try { BlockInfo d(bytesConstRef(it->value())); - _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; + _out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; } catch (...) { cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); @@ -293,11 +293,11 @@ void BlockChain::rebuild(std::string const& _path, std::function parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1); + cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); return; } lastHash = bi.hash(); @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -461,21 +461,21 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Work out its number as the parent's number + 1 - if (!isKnown(_block.info.parentHash)) + if (!isKnown(_block.info.parentHash())) { - clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash(); // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_block.info.parentHash); + auto pd = details(_block.info.parentHash()); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_block.info.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; + auto parentBlock = block(_block.info.parentHash()); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash()); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number(); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -483,9 +483,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Check it's not crazy - if (_block.info.timestamp > (u256)time(0)) + if (_block.info.timestamp() > (u256)time(0)) { - clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } @@ -543,9 +543,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_block.info.parentHash); + details(_block.info.parentHash()); DEV_WRITE_GUARDED(x_details) - m_details[_block.info.parentHash].children.push_back(_block.info.hash()); + m_details[_block.info.parentHash()].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); @@ -554,9 +554,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp())); - extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); @@ -585,10 +585,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif - // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; h256 common; @@ -599,7 +599,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash()); route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be @@ -630,15 +630,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Collate logs into blooms. h256s alteredBlooms; { - LogBloom blockBloom = tbi.logBloom; - blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); + LogBloom blockBloom = tbi.logBloom(); + blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref())); // Pre-memoize everything we need before locking x_blocksBlooms - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) blocksBlooms(chunkId(level, index / c_bloomIndexSize)); WriteGuard l(x_blocksBlooms); - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) { unsigned i = index / c_bloomIndexSize; unsigned o = index % c_bloomIndexSize; @@ -661,23 +661,23 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& ReadGuard l1(x_blocksBlooms); for (auto const& h: alteredBlooms) extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); - extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); + extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); } // FINALLY! change our best hash. { newLastBlockHash = _block.info.hash(); - newLastBlockNumber = (unsigned)_block.info.number; + newLastBlockNumber = (unsigned)_block.info.number(); } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; #if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif } @@ -750,7 +750,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& checkBest = t.elapsed(); if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number(); cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; @@ -758,7 +758,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; cnote << " " << _block.transactions.size() << " transactions"; - cnote << " " << _block.info.gasUsed << " gas used"; + cnote << " " << _block.info.gasUsed() << " gas used"; } #endif @@ -861,7 +861,7 @@ void BlockChain::rescue(OverlayDB& _db) cout << "extras..." << flush; details(h); cout << "state..." << flush; - if (_db.exists(bi.stateRoot)) + if (_db.exists(bi.stateRoot())) break; } catch (...) {} @@ -1233,19 +1233,3 @@ State BlockChain::genesisState(OverlayDB const& _db) return ret; } - - - - - - - - - - - - - - - - diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50965f2b6..3ff85c8a6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -391,7 +391,7 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash)); + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index a59326b77..64d1bb197 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr _peer) unsigned BlockChainSync::estimatedHashes() const { BlockInfo block = host().chain().info(); - time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp(); time_t now = time(0); unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) @@ -220,9 +220,9 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); - if (bi.number > maxUnknownNumber) + if (bi.number() > maxUnknownNumber) { - maxUnknownNumber = bi.number; + maxUnknownNumber = bi.number(); maxUnknown = h; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6b400b236..c9ee4c1cf 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,8 +101,8 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.sha3Uncles = work.hash; - bi.parentHash = work.parentHash; + bi.setSha3Uncles(work.hash); + bi.setParentHash(work.parentHash); m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.sha3Uncles == work.hash) + if (it->verified.info.sha3Uncles() == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,11 +136,11 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash) { // we're next! m_verifying.pop_front(); - if (m_knownBad.count(res.verified.info.parentHash)) + if (m_knownBad.count(res.verified.info.parentHash())) { m_readySet.erase(res.verified.info.hash()); m_knownBad.insert(res.verified.info.hash()); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.sha3Uncles == work.hash) + if (i.verified.info.sha3Uncles() == work.hash) { i = move(res); goto OK; @@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() { while (!m_verifying.empty() && !m_verifying.front().blockData.empty()) { - if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + if (m_knownBad.count(m_verifying.front().verified.info.parentHash())) { m_readySet.erase(m_verifying.front().verified.info.hash()); m_knownBad.insert(m_verifying.front().verified.info.hash()); @@ -213,7 +213,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) return ImportResult::Malformed; } - clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash(); // Check block doesn't already exist first! if (m_bc->isKnown(h)) @@ -227,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // Check it's not in the future (void)_isOurs; - if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) + if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/) { - m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); + m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes()))); char buf[24]; - time_t bit = (unsigned)bi.timestamp; + time_t bit = (unsigned)bi.timestamp(); if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails - clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp() << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); + m_difficulty += bi.difficulty(); + bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash()); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. - if (m_knownBad.count(bi.parentHash)) + if (m_knownBad.count(bi.parentHash())) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash())) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; - m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash(); + m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_unknownCount++; return ImportResult::UnknownParent; @@ -268,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash(), _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_knownCount++; noteReady_WITH_LOCK(h); @@ -295,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::vector oldVerified; swap(m_verified, oldVerified); for (auto& b: oldVerified) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash())) { m_knownBad.insert(b.verified.info.hash()); m_readySet.erase(b.verified.info.hash()); @@ -321,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles())) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles(); m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); @@ -460,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; + m_drainingDifficulty += bs.verified.info.difficulty(); m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 866c9c8f9..e58e1a8c6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), + m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)), m_depth(_level) {} @@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction) // Avoid transactions that would take us beyond the block gas limit. u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) + if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit()) { - clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; - BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas())); } // Check gas cost is enough. @@ -403,7 +403,7 @@ void Executive::finalize() m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); - m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); + m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned); // Suicides... if (m_ext) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ee2078a07..64daaf5f8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -105,7 +105,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock.clear(); m_currentBlock.clear(); -// assert(m_state.root() == m_previousBlock.stateRoot); +// assert(m_state.root() == m_previousBlock.stateRoot()); paranoia("end of normal construction.", true); } @@ -123,16 +123,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& auto b = _bc.block(_h); BlockInfo bi(b); - if (bi.number) + if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + BlockInfo bip(_bc.block(bi.parentHash())); + sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. - m_ourAddress = bi.coinbaseAddress; + m_ourAddress = bi.coinbaseAddress(); Timer t; auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); @@ -338,9 +338,9 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - if (m_db.lookup(bi.stateRoot).empty()) + if (m_db.lookup(bi.stateRoot()).empty()) { - cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; + cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); @@ -357,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash()); // push back for later replay. - bi.populate(_bc.block(bi.parentHash)); // move to parent. + bi.populate(_bc.block(bi.parentHash())); // move to parent. } m_previousBlock = bi; @@ -402,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif // Check family: - BlockInfo biParent = _bc.info(_block.info.parentHash); + BlockInfo biParent = _bc.info(_block.info.parentHash()); _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -411,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif BlockInfo biGrandParent; - if (biParent.number) - biGrandParent = _bc.info(biParent.parentHash); + if (biParent.number()) + biGrandParent = _bc.info(biParent.parentHash()); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo()); + sync(_bc, _block.info.parentHash(), BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -462,17 +462,15 @@ void State::resetCurrent() m_cache.clear(); m_touched.clear(); m_currentBlock = BlockInfo(); - m_currentBlock.coinbaseAddress = m_ourAddress; - m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); - m_currentBlock.transactionsRoot = h256(); - m_currentBlock.sha3Uncles = h256(); + m_currentBlock.setCoinbaseAddress(m_ourAddress); + m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0))); m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); m_committedToMine = false; @@ -538,7 +536,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu catch (BlockGasLimitReached const& e) { bigint const& got = *boost::get_error_info(e); - if (got > m_currentBlock.gasLimit) + if (got > m_currentBlock.gasLimit()) { clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; _tq.drop(t.sha3()); @@ -583,7 +581,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number()); string ret; unsigned i = 0; @@ -604,12 +602,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == _block.info.parentHash); - assert(m_currentBlock.parentHash == _block.info.parentHash); - assert(rootHash() == m_previousBlock.stateRoot); + assert(m_previousBlock.hash() == _block.info.parentHash()); + assert(m_currentBlock.parentHash() == _block.info.parentHash()); + assert(rootHash() == m_previousBlock.stateRoot()); #endif - if (m_currentBlock.parentHash != m_previousBlock.hash()) + if (m_currentBlock.parentHash() != m_previousBlock.hash()) // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); @@ -622,7 +620,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) LastHashes lh; DEV_TIMED_ABOVE("lastHashes", 500) - lh = _bc.lastHashes((unsigned)m_previousBlock.number); + lh = _bc.lastHashes((unsigned)m_previousBlock.number()); RLP rlp(_block.block); @@ -651,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) } h256 receiptsRoot; - DEV_TIMED_ABOVE("receiptsRoot", 500) + DEV_TIMED_ABOVE(".receiptsRoot()", 500) receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) + if (receiptsRoot != m_currentBlock.receiptsRoot()) { InvalidReceiptsStateRoot ex; - ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot()); ex << errinfo_receipts(receipts); ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } - if (m_currentBlock.logBloom != logBloom()) + if (m_currentBlock.logBloom() != logBloom()) { InvalidLogBloom ex; - ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom()); ex << errinfo_receipts(receipts); BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. - u256 tdIncrease = m_currentBlock.difficulty; + u256 tdIncrease = m_currentBlock.difficulty(); // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) @@ -686,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) vector rewarded; h256Hash excluded; DEV_TIMED_ABOVE("allKin", 500) - excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; @@ -710,22 +708,22 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) + if (!_bc.isKnown(uncle.parentHash())) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + uncleParent = BlockInfo(_bc.block(uncle.parentHash())); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7) { UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } - else if (uncle.number == m_currentBlock.number) + else if (uncle.number() == m_currentBlock.number()) { UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } uncle.verifyParent(uncleParent); @@ -748,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash()) { m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot())); } - if (m_currentBlock.gasUsed != gasUsed()) + if (m_currentBlock.gasUsed() != gasUsed()) { // Rollback the trie. m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed()))); } return tdIncrease; @@ -772,7 +770,7 @@ void State::cleanup(bool _fullCommit) // Commit the new trie to disk. if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -786,7 +784,7 @@ void State::cleanup(bool _fullCommit) m_db.commit(); if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -806,7 +804,7 @@ void State::uncommitToMine() { m_cache.clear(); if (!m_transactions.size()) - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); else m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; @@ -878,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock.number != 0) + if (m_previousBlock.number() != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); - auto p = m_previousBlock.parentHash; +// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl; + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; @@ -926,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = hash256(transactionsMap); - m_currentBlock.receiptsRoot = hash256(receiptsMap); - m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); - // Apply rewards last of all. applyRewards(uncleBlockHeaders); @@ -941,12 +934,18 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // cnote << m_state; // cnote << *this; - m_currentBlock.gasUsed = gasUsed(); - m_currentBlock.stateRoot = m_state.root(); - m_currentBlock.parentHash = m_previousBlock.hash(); - m_currentBlock.extraData = _extraData; - if (m_currentBlock.extraData.size() > 32) - m_currentBlock.extraData.resize(32); + m_currentBlock.setLogBloom(logBloom()); + m_currentBlock.setGasUsed(gasUsed()); + m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root()); + + m_currentBlock.setParentHash(m_previousBlock.hash()); + m_currentBlock.setExtraData(_extraData); + if (m_currentBlock.extraData().size() > 32) + { + auto ed = m_currentBlock.extraData(); + ed.resize(32); + m_currentBlock.setExtraData(ed); + } m_committedToMine = true; } @@ -967,13 +966,13 @@ bool State::sealBlock(bytesConstRef _header) ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); - cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; + cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")"; // TODO: move into Sealer StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), "", // Can't give the nonce here. "", //TODO: chain head hash here ?? - m_currentBlock.parentHash.abridged() + m_currentBlock.parentHash().abridged() ); // Quickly reset the transactions. @@ -1270,7 +1269,7 @@ State State::fromPending(unsigned _i) const ret.m_cache.clear(); _i = min(_i, m_transactions.size()); if (!_i) - ret.m_state.setRoot(m_previousBlock.stateRoot); + ret.m_state.setRoot(m_previousBlock.stateRoot()); else ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) @@ -1287,10 +1286,10 @@ void State::applyRewards(vector const& _uncleBlockHeaders) u256 r = m_blockReward; for (auto const& i: _uncleBlockHeaders) { - addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8); + addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8); r += m_blockReward / 32; } - addBalance(m_currentBlock.coinbaseAddress, r); + addBalance(m_currentBlock.coinbaseAddress(), r); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) diff --git a/libethereum/State.h b/libethereum/State.h index 805215ee5..e2bda6f24 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } + u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); } /// Check if the address is in use. bool addressInUse(Address _address) const; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..a5c45af26 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -83,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry ): LogEntry(_le), blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), + blockNumber((BlockNumber)_bi.number()), transactionHash(_th), transactionIndex(_ti), logIndex(_li), @@ -205,7 +205,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } + h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2b2ada0ae..f95481c54 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress()); break; case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); + m_stack.push_back(_ext.currentBlock.timestamp()); break; case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); + m_stack.push_back(_ext.currentBlock.number()); break; case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); + m_stack.push_back(_ext.currentBlock.difficulty()); break; case Instruction::GASLIMIT: - m_stack.push_back(_ext.currentBlock.gasLimit); + m_stack.push_back(_ext.currentBlock.gasLimit()); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libtestutils/BlockChainLoader.cpp b/libtestutils/BlockChainLoader.cpp index e6c47e2fe..7e08243af 100644 --- a/libtestutils/BlockChainLoader.cpp +++ b/libtestutils/BlockChainLoader.cpp @@ -36,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) // load genesisBlock m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); - assert(m_state.rootHash() == m_bc->info().stateRoot); + assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks for (auto const& block: _json["blocks"]) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 15d39bded..fae12708c 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -88,18 +88,18 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) if (_bi) { res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["parentHash"] = toJS(_bi.parentHash()); + res["sha3Uncles"] = toJS(_bi.sha3Uncles()); + res["miner"] = toJS(_bi.coinbaseAddress()); + res["stateRoot"] = toJS(_bi.stateRoot()); + res["transactionsRoot"] = toJS(_bi.transactionsRoot()); res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); + res["number"] = toJS(_bi.number()); res["gasUsed"] = toJS(_bi.gasUsed); res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["logsBloom"] = toJS(_bi.logBloom); + res["timestamp"] = toJS(_bi.timestamp()); + res["extraData"] = toJS(_bi.extraData()); + res["logsBloom"] = toJS(_bi.logBloom()); res["target"] = toJS(_bi.boundary()); // TODO: move into ProofOfWork. @@ -140,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number())); } return res; } @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()); + res["stateRoot"] = toJS(_t.stateRoot()()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b43c4db51..bae980a7e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -151,12 +151,12 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); m_environment.currentBlock.number = toInt(_o["currentNumber"]); m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 9ee93779e..7dbc5c91e 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(blocks) u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString()); h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString())); h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); - ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom); - ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress); + ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); + ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), - _blockInfo.extraData.begin(), - _blockInfo.extraData.end() + _blockInfo.extraData().begin(), + _blockInfo.extraData().end() ); ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); @@ -132,11 +132,11 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); - ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp); - ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles); + ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); + ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; BlockInfo blockInfo = _client.blockInfo(blockHash); diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 20f60618f..cf44dfd9f 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -66,7 +66,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,9 +76,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot = trueState.rootHash(); + biGenesisBlock.stateRoot() = trueState.rootHash(); else - TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -125,7 +125,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TransientDirectory td_stateDB, td_bc; BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -225,7 +225,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); updatePoW(current_BlockHeader); } @@ -302,7 +302,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (o.count("expect") > 0) { stateOptionsMap expectStateMap; - State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); @@ -313,7 +313,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section - State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); }//_fillin @@ -374,19 +374,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); @@ -551,7 +551,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp = (u256)time(0); + uncleBlockFromFields.timestamp() = (u256)time(0); cnote << "uncle block n = " << toString(uncleBlockFromFields.number); if (_vBiBlocks.size() > 2) { @@ -568,15 +568,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash; - uncleBlockFromFields.stateRoot = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot; + uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); + uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); if (overwrite == "timestamp") { - uncleBlockFromFields.timestamp = toInt(uncleHeaderObj["timestamp"]); + uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); } } @@ -660,19 +660,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { BlockInfo tmp = _header; if (ho.count("parentHash")) - tmp.parentHash = h256(ho["parentHash"].get_str()); + tmp.parentHash() = h256(ho["parentHash"].get_str()); if (ho.count("uncleHash")) - tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); if (ho.count("coinbase")) - tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); if (ho.count("stateRoot")) - tmp.stateRoot = h256(ho["stateRoot"].get_str()); + tmp.stateRoot() = h256(ho["stateRoot"].get_str()); if (ho.count("transactionsTrie")) - tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); if (ho.count("receiptTrie")) - tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); if (ho.count("bloom")) - tmp.logBloom = LogBloom(ho["bloom"].get_str()); + tmp.logBloom() = LogBloom(ho["bloom"].get_str()); if (ho.count("difficulty")) tmp.difficulty = toInt(ho["difficulty"]); if (ho.count("number")) @@ -682,9 +682,9 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) if (ho.count("gasUsed")) tmp.gasUsed = toInt(ho["gasUsed"]); if (ho.count("timestamp")) - tmp.timestamp = toInt(ho["timestamp"]); + tmp.timestamp() = toInt(ho["timestamp"]); if (ho.count("extraData")) - tmp.extraData = importByteArray(ho["extraData"].get_str()); + tmp.extraData() = importByteArray(ho["extraData"].get_str()); // find new valid nonce if (tmp != _header && tmp.difficulty) @@ -751,19 +751,19 @@ mArray writeTransactionsToJson(Transactions const& txs) mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) { - _o["parentHash"] = toString(_bi.parentHash); - _o["uncleHash"] = toString(_bi.sha3Uncles); - _o["coinbase"] = toString(_bi.coinbaseAddress); - _o["stateRoot"] = toString(_bi.stateRoot); - _o["transactionsTrie"] = toString(_bi.transactionsRoot); - _o["receiptTrie"] = toString(_bi.receiptsRoot); - _o["bloom"] = toString(_bi.logBloom); + _o["parentHash"] = toString(_bi.parentHash()); + _o["uncleHash"] = toString(_bi.sha3Uncles()); + _o["coinbase"] = toString(_bi.coinbaseAddress()); + _o["stateRoot"] = toString(_bi.stateRoot()); + _o["transactionsTrie"] = toString(_bi.transactionsRoot()); + _o["receiptTrie"] = toString(_bi.receiptsRoot()); + _o["bloom"] = toString(_bi.logBloom()); _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); - _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); + _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); _o["hash"] = toString(_bi.hash()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 02ff4517a..2d5a2faa6 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index fdfb180fb..28b2e43ab 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -83,10 +83,10 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st mObject FakeExtVM::exportEnv() { mObject ret; - ret["previousHash"] = toString(currentBlock.parentHash); + ret["previousHash"] = toString(currentBlock.parentHash()); ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); - ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp, HexPrefix::Add, 1); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); return ret; @@ -102,13 +102,13 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash = h256(_o["previousHash"].get_str()); + currentBlock.parentHash() = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } mObject FakeExtVM::exportState() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d44545145..4a6507cd6 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1188,7 +1188,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " return block.timestamp() == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/third/MainWin.cpp b/third/MainWin.cpp index f2a90cc0b..a3b05572f 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From 0d6170267aabb2369abd9d7522b781eeccff1391 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:34:11 +0200 Subject: [PATCH 093/113] Minor fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ec37302a2..357926d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -98,7 +98,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + bc().rescue(m_stateDB); m_gp->update(bc()); From a6194d2d219c8eddda11a6bbd9a681061835b546 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 11:43:23 +0200 Subject: [PATCH 094/113] fixed build --- evmjit/libevmjit-cpp/JitVM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 4e1fb66ea..d96da87c1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -42,10 +42,10 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); - m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); - m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); - m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); + m_data.difficulty = eth2jit(_ext.currentBlock.difficulty()); + m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit()); + m_data.number = static_cast(_ext.currentBlock.number()); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); From f7500218c812d36f15e074e77cb56137c68d0ce1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 16:45:23 +0200 Subject: [PATCH 095/113] mix working --- CMakeLists.txt | 28 +++++++------- alethzero/MainWin.cpp | 53 ++++++++++++++------------- alethzero/MiningView.cpp | 4 +- alethzero/MiningView.h | 4 +- exp/CMakeLists.txt | 4 +- libethereum/BlockChain.cpp | 1 - libtestutils/BlockChainLoader.cpp | 3 +- libtestutils/StateLoader.cpp | 2 +- libtestutils/StateLoader.h | 2 + libweb3jsonrpc/JsonHelper.cpp | 8 ++-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libwebthree/WebThree.cpp | 2 +- mix/ClientModel.cpp | 4 +- mix/MixClient.cpp | 36 +++++++++--------- mix/MixClient.h | 36 +++++++++++++++--- 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b410d875c..89d3c167a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,13 +403,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) -# add_subdirectory(libweb3jsonrpc) + add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) -# add_subdirectory(libjsengine) -# add_subdirectory(libjsconsole) -# add_subdirectory(ethconsole) + add_subdirectory(libjsengine) + add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -437,31 +437,31 @@ add_subdirectory(libethcore) if (GENERAL) add_subdirectory(libevm) add_subdirectory(libethereum) -# add_subdirectory(libwebthree) + add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) -# add_subdirectory(ethminer) + add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) -# add_subdirectory(ethkey) + add_subdirectory(ethkey) endif () if (TESTS) -# add_subdirectory(libtestutils) -# add_subdirectory(test) + add_subdirectory(libtestutils) + add_subdirectory(test) if (JSONRPC) -# add_subdirectory(ethrpctest) + add_subdirectory(ethrpctest) endif () endif () if (TOOLS) -# add_subdirectory(rlp) -# add_subdirectory(abi) -# add_subdirectory(ethvm) -# add_subdirectory(eth) + add_subdirectory(rlp) + add_subdirectory(abi) + add_subdirectory(ethvm) + add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ad8f5528c..181772ddb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,9 +189,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; - auto block = CanonBlockChain::createGenesisBlock(); - cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl; @@ -208,13 +208,14 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); @@ -1124,7 +1125,7 @@ void Main::refreshMining() QString t; if (gp.first != EthashAux::NotGenerating) t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second); - MiningProgress p = ethereum()->miningProgress(); + WorkingProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining")); if (ethereum()->isMining() && p.hashes > 0) { @@ -1629,7 +1630,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1699,7 +1700,7 @@ void Main::on_blocks_currentItemChanged() auto details = ethereum()->blockChain().details(h); auto blockData = ethereum()->blockChain().block(h); auto block = RLP(blockData); - BlockInfo info(blockData); + Ethash::BlockHeader info(blockData); stringstream s; @@ -1709,21 +1710,21 @@ void Main::on_blocks_currentItemChanged() time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; - s << "

#" << info.number; + s << "

#" << info.number(); s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
"; s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; - s << "
Mix hash: " << info.mixHash << "" << "
"; - s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; - s << "
Difficulty: " << info.difficulty << "" << "
"; - if (info.number) + s << "
Mix hash: " << info.mixHash() << "" << "
"; + s << "
Nonce: " << info.nonce() << "" << "
"; + s << "
Hash w/o nonce: " << info.hashWithout() << "" << "
"; + s << "
Difficulty: " << info.difficulty() << "" << "
"; + if (info.number()) { - auto e = EthashAux::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce()); + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash() << "" << "
"; } else @@ -1740,19 +1741,19 @@ void Main::on_blocks_currentItemChanged() s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { - BlockInfo uncle = BlockInfo::fromHeader(u.data()); + Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; s << line << "Parent: " << uncle.parentHash() << "" << ""; - s << line << "Number: " << uncle.number << "" << ""; + s << line << "Number: " << uncle.number() << "" << ""; s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; - s << line << "Mix hash: " << uncle.mixHash << "" << ""; - s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Mix hash: " << uncle.mixHash() << "" << ""; + s << line << "Nonce: " << uncle.nonce() << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; - s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = EthashAux::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; + s << line << "Difficulty: " << uncle.difficulty() << "" << ""; + auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce()); + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash()) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; @@ -1764,7 +1765,7 @@ void Main::on_blocks_currentItemChanged() unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } s << "
Post: " << info.stateRoot() << "" << "
"; @@ -1807,7 +1808,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index e020408ea..fb9de0346 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MiningProgress; +using dev::eth::WorkingProgress; // functions using dev::toString; @@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MiningProgress const& _p) +void MiningView::appendStats(list const& _i, WorkingProgress const& _p) { (void)_p; if (_i.empty()) diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 65b9f2ec9..ae81a7cc4 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); + void appendStats(std::list const& _l, dev::eth::WorkingProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MiningProgress m_progress; + dev::eth::WorkingProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 5f876a69b..a9bc09db7 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,10 +18,10 @@ if (READLINE_FOUND) endif() if (JSONRPC) -# target_link_libraries(${EXECUTABLE} web3jsonrpc) + target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -#target_link_libraries(${EXECUTABLE} webthree) +target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b696c77bd..03ab1b46a 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -137,7 +137,6 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map #include "BlockChainLoader.h" #include "StateLoader.h" #include "Common.h" @@ -35,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) m_state = sl.state(); // load genesisBlock - m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); + m_bc.reset(new FullBlockChain(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill)); assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks diff --git a/libtestutils/StateLoader.cpp b/libtestutils/StateLoader.cpp index 235f1c573..cd5c37e96 100644 --- a/libtestutils/StateLoader.cpp +++ b/libtestutils/StateLoader.cpp @@ -27,7 +27,7 @@ using namespace dev::eth; using namespace dev::test; StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): - m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty) + m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty) { for (string const& name: _json.getMemberNames()) { diff --git a/libtestutils/StateLoader.h b/libtestutils/StateLoader.h index 47eb26900..c66f53148 100644 --- a/libtestutils/StateLoader.h +++ b/libtestutils/StateLoader.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace dev { @@ -38,6 +39,7 @@ class StateLoader public: StateLoader(Json::Value const& _json, std::string const& _dbPath); eth::State const& state() const { return m_state; } + eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; } private: eth::State m_state; diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index fae12708c..54fde52e8 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -93,10 +93,10 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["miner"] = toJS(_bi.coinbaseAddress()); res["stateRoot"] = toJS(_bi.stateRoot()); res["transactionsRoot"] = toJS(_bi.transactionsRoot()); - res["difficulty"] = toJS(_bi.difficulty); + res["difficulty"] = toJS(_bi.difficulty()); res["number"] = toJS(_bi.number()); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); + res["gasUsed"] = toJS(_bi.gasUsed()); + res["gasLimit"] = toJS(_bi.gasLimit()); res["timestamp"] = toJS(_bi.timestamp()); res["extraData"] = toJS(_bi.extraData()); res["logsBloom"] = toJS(_bi.logBloom()); @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()()); + res["stateRoot"] = toJS(_t.stateRoot()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 3aff9cf23..bf49d3322 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str return true; } -dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +dev::eth::BlockChain const& WebThreeStubServer::bc() const { return m_web3.ethereum()->blockChain(); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4d545c90e..2860f852b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -34,7 +34,7 @@ namespace eth { class KeyManager; class TrivialGasPricer; -class CanonBlockChain; +class BlockChain; class BlockQueue; } @@ -89,7 +89,7 @@ private: private: h256 blockHash(std::string const& _blockNumberOrHash) const; - dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockChain const& bc() const; dev::eth::BlockQueue const& bq() const; dev::WebThreeDirect& m_web3; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 3c1dea40f..7889b5935 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect( Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) { - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); + m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr(), _dbPath, _we, 0)); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 90ff19feb..5c5f2f4cd 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); stringstream strGas; - strGas << blockInfo.gasUsed; + strGas << blockInfo.gasUsed(); stringstream strNumber; - strNumber << blockInfo.number; + strNumber << blockInfo.number(); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ea4686601..eef6ad6ec 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -24,12 +24,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include "Exceptions.h" using namespace std; @@ -45,22 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho namespace { +} -struct MixPow //dummy POW +MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot): + FullBlockChain(createGenesisBlock(_stateRoot), std::unordered_map(), _path, WithExisting::Kill) { - typedef int Solution; - static bool verify(BlockInfo const&) { return true; } -}; - } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(15) + block.appendList(13) << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); + << std::string(); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -78,7 +77,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,12 +89,13 @@ void MixClient::resetState(std::unordered_map const& _accounts SecureTrieDB accountState(&m_stateDB); accountState.init(); - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + dev::eth::commit(_accounts, accountState); h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); + State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + s.sync(bc()); + m_state = s; m_startState = m_state; WriteGuard lx(x_executions); m_executions.clear(); @@ -275,11 +274,14 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + + NoProof::BlockHeader h(m_state.info()); + RLPStream header; + h.streamRLP(header); + m_state.sealBlock(header.out()); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; } ExecutionResult MixClient::lastExecution() const @@ -383,9 +385,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MiningProgress MixClient::miningProgress() const +eth::WorkingProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::WorkingProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..279692de5 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,13 +33,40 @@ namespace dev { + namespace mix { -class MixBlockChain: public dev::eth::BlockChain +class NoProof +{ + class BlockHeaderRaw: public dev::eth::BlockInfo + { + public: + static const unsigned SealFields = 0; + + protected: + BlockHeaderRaw() = default; + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; } + void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; } + void streamRLPFields(RLPStream& _s) const { (void) _s; } + }; + +public: + + static std::string name() { return "NoProof"; } + static unsigned revision() { return 0; } + using BlockHeader = dev::eth::BlockHeaderPolished; + +private: + static AddressHash s_authorities; +}; + +class MixBlockChain: public dev::eth::FullBlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {} + MixBlockChain(std::string const& _path, h256 _stateRoot); static bytes createGenesisBlock(h256 _stateRoot); }; @@ -67,9 +95,7 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MiningProgress miningProgress() const override; - eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } - bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } + eth::WorkingProgress miningProgress() const override; virtual void flushTransactions() override {} /// @returns the last mined block information From 3737590f22cd73f2ec39d85703c247993876879e Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 18:11:08 +0200 Subject: [PATCH 096/113] started tests refactoring --- libethcore/Common.h | 3 ++- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 9 +++++---- libethereum/BlockQueue.cpp | 2 +- libethereum/Client.cpp | 3 +-- mix/MixClient.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libethcore/dagger.cpp | 4 ++-- test/libethereum/ClientBase.cpp | 14 +++++++------- test/libethereum/genesis.cpp | 6 +++--- test/libethereum/stateOriginal.cpp | 5 +++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 5c0a0cc79..116e1d5ed 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -130,9 +130,10 @@ struct ImportRequirements TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, None = 0 }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 03ab1b46a..8a654fa51 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 3ff85c8a6..811da8609 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -118,12 +118,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -391,7 +391,8 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash())); + if ((_ir & ImportRequirements::Parent) != 0) + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c9ee4c1cf..d0ca34b1c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); } catch (...) { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 357926d03..d43f240b7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -84,10 +84,9 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database // until after the construction. m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); - m_preMine = State(m_stateDB); - m_postMine = State(m_stateDB); // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. m_preMine = bc().genesisState(m_stateDB); + m_postMine = m_preMine; m_bq.setChain(bc()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index eef6ad6ec..67f2a2507 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -279,7 +279,7 @@ void MixClient::mine() RLPStream header; h.streamRLP(header); m_state.sealBlock(header.out()); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bae980a7e..30f323369 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,7 +63,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 061b5ae79..8d4cba933 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); - BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); + BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); BOOST_REQUIRE_EQUAL(nonce, header.nonce); unsigned cacheSize(o["cache_size"].get_int()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 7dbc5c91e..a426ff53f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -119,21 +119,21 @@ BOOST_AUTO_TEST_CASE(blocks) h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); - ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); + ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty()); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), _blockInfo.extraData().begin(), _blockInfo.extraData().end() ); - ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); - ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); + ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit()); + ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed()); ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash()); - ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); - ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); - ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); + ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash()); + ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce()); + ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number()); ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 2d5a2faa6..39997572f 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,9 +60,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e3f8ac29f..163c89e50 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ BOOST_AUTO_TEST_CASE(Complex) Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; + OverlayDB stateDB = State::openDB(h256()); + CanonBlockChain bc; cout << bc; State s = bc.genesisState(stateDB); From 1c1e9aea02a541f5c95a406b06d280a3f198f218 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 20:53:58 +0200 Subject: [PATCH 097/113] eth working --- eth/main.cpp | 2 +- ethminer/MinerAux.h | 26 ++++++++++++-------------- libethcore/BlockInfo.h | 1 + libethereum/Client.h | 6 +++++- test/TestHelper.cpp | 17 ++++++++++++----- test/libethcore/dagger.cpp | 6 +++--- test/libethereum/ClientBase.cpp | 4 ++-- test/libethereum/gaspricer.cpp | 3 ++- test/libevm/vm.cpp | 10 +++++----- 9 files changed, 43 insertions(+), 32 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 7ce4d49c2..0b83c97b4 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1310,7 +1310,7 @@ int main(int argc, char** argv) { try { - CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); } catch (...) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 0d227b1ef..01083012f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -397,17 +397,16 @@ public: private: void doInitDAG(unsigned _n) { - BlockInfo bi; - bi.number() = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; - Ethash::prep(bi); + h256 seedHash = EthashAux::seedHash(_n); + cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl; + EthashAux::full(seedHash, true); exit(0); } void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) { - BlockInfo genesis; - genesis.difficulty = 1 << 18; + Ethash::BlockHeader genesis; + genesis.setDifficulty(1 << 18); cdebug << genesis.boundary(); GenericFarm f; @@ -417,17 +416,16 @@ private: cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; - Ethash::prep(genesis); + genesis.prep(); - genesis.difficulty = u256(1) << 63; - genesis.noteDirty(); + genesis.setDifficulty(u256(1) << 63); f.setWork(genesis); if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); - map results; + map results; uint64_t mean = 0; uint64_t innerMean = 0; for (unsigned i = 0; i <= _trials; ++i) @@ -488,9 +486,9 @@ private: Farm rpc(client); GenericFarm f; if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 67a5397f4..c310b3dd9 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -128,6 +128,7 @@ public: void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } Address const& coinbaseAddress() const { return m_coinbaseAddress; } h256 const& stateRoot() const { return m_stateRoot; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 73609bd71..4523d324b 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -77,7 +77,7 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); * @brief Main API hub for interfacing with Ethereum. * Not to be used directly - subclass. */ -class Client: public ClientBase, Worker +class Client: public ClientBase, protected Worker { public: /// New-style Constructor. @@ -342,6 +342,8 @@ public: init(_host, _dbPath, _forceAction, _networkId); } + virtual ~SpecialisedClient() { stopWorking(); } + /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } @@ -365,6 +367,8 @@ public: u256 _networkId = 0 ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + virtual ~EthashClient() { stopWorking(); } + /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. virtual std::tuple getEthashWork() override; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 30f323369..c29788b9f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -63,11 +64,17 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + Ethash::BlockHeader header(s.info); + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { - return completed = s.completeMine(sol); + header.m_mixHash = sol.mixHash; + header.m_nonce = sol.nonce; + RLPStream ret; + header.streamRLP(ret); + s.sealBlock(ret); + return true; }); f.setWork(s.info()); f.startCPU(); @@ -77,9 +84,9 @@ void mine(State& s, BlockChain const& _bc) void mine(BlockInfo& _bi) { - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { _bi.proof = sol; return completed = true; diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 8d4cba933..c3cd75b0d 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(basic_test) h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); - BOOST_REQUIRE_EQUAL(nonce, header.nonce); + BOOST_REQUIRE_EQUAL(nonce, header.nonce()); unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - EthashProofOfWork::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header.seedHash(), header.hashWithout(), header.nonce()); BOOST_REQUIRE_EQUAL(r.value, result); - BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); + BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash()); } } diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index a426ff53f..f9d83e9c6 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber); // blockInfo - auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void + auto compareBlockInfos = [](Json::Value const& _b, Ethash::BlockHeader _blockInfo) -> void { LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString())); Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString())); @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - BlockInfo blockInfo = _client.blockInfo(blockHash); + Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index ce49a4a20..050ab2d25 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer) std::shared_ptr gp(new TrivialGasPricer); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); - gp->update(BlockChain(bytes(), TransientDirectory().path(), WithExisting::Kill)); + gp->update(FullBlockChain(bytes(), StateDefinition(), TransientDirectory().path(), WithExisting::Kill)); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 28b2e43ab..badabd70c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number()), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -84,11 +84,11 @@ mObject FakeExtVM::exportEnv() { mObject ret; ret["previousHash"] = toString(currentBlock.parentHash()); - ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); + ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1); ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); - ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); - ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); + ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1); + ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1); return ret; } @@ -107,7 +107,7 @@ void FakeExtVM::importEnv(mObject& _o) lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } From 374b1960f776471155e5797187f37808177ad2cd Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 18 Jul 2015 15:19:15 +0200 Subject: [PATCH 098/113] tests repared --- libethcore/BlockInfo.h | 2 +- libethereum/BlockChain.h | 7 +- test/TestHelper.cpp | 109 +++++++---- test/TestHelper.h | 19 +- test/fuzzTesting/checkRandomStateTest.cpp | 2 +- test/fuzzTesting/createRandomStateTest.cpp | 2 +- test/libethcore/dagger.cpp | 2 +- test/libethereum/ClientBase.cpp | 3 +- test/libethereum/blockchain.cpp | 203 ++++++++++----------- test/libethereum/genesis.cpp | 2 +- test/libethereum/state.cpp | 2 +- test/libevm/vm.cpp | 27 ++- 12 files changed, 221 insertions(+), 159 deletions(-) diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index c310b3dd9..8d5264361 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -209,7 +209,7 @@ public: void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); - BlockInfo::parentHash = _parent.hash(); + BlockInfo::m_parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); BlockInfoSub::populateFromParent(_parent); } diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 811da8609..7b89d3f99 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -392,7 +392,12 @@ public: BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); if ((_ir & ImportRequirements::Parent) != 0) - h.verifyParent(header(h.parentHash())); + { + bytes parentHeader(headerData(h.parentHash())); + if (parentHeader.empty()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + h.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, h.parentHash(), HeaderData)); + } res.info = static_cast(h); } catch (Exception& ex) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index c29788b9f..aec72285c 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,38 +63,23 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { + std::unique_ptr sealer(Ethash::createSealEngine()); s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - Ethash::BlockHeader header(s.info); - f.onSolutionFound([&](EthashProofOfWork::Solution sol) - { - header.m_mixHash = sol.mixHash; - header.m_nonce = sol.nonce; - RLPStream ret; - header.streamRLP(ret); - s.sealBlock(ret); - return true; - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); -} - -void mine(BlockInfo& _bi) -{ - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](EthashProofOfWork::Solution sol) - { - _bi.proof = sol; - return completed = true; - }); - f.setWork(_bi); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + sealer->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + sealer->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); +} + +void mine(Ethash::BlockHeader& _bi) +{ + std::unique_ptr sealer(Ethash::createSealEngine()); + Notified sealed; + sealer->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + sealer->generateSeal(_bi); + sealed.waitNot({}); + _bi = Ethash::BlockHeader(sealed); } } @@ -158,13 +143,24 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); - m_environment.currentBlock.number = toInt(_o["currentNumber"]); - m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); - m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); - + RLPStream rlpStream; + rlpStream.appendList(BlockInfo::BasicFields); + + rlpStream << h256(_o["previousHash"].get_str()); + rlpStream << EmptyListSHA3; + rlpStream << Address(_o["currentCoinbase"].get_str()); + rlpStream << h256(); // stateRoot + rlpStream << EmptyTrie; // transactionTrie + rlpStream << EmptyTrie; // receiptTrie + rlpStream << LogBloom(); // bloom + rlpStream << toInt(_o["currentDifficulty"]); + rlpStream << toInt(_o["currentNumber"]); + rlpStream << toInt(_o["currentGasLimit"]); + rlpStream << 0; //gasUsed + rlpStream << toInt(_o["currentTimestamp"]); + rlpStream << std::string(); //extra data + + m_environment.currentBlock = BlockInfo(rlpStream.out(), CheckEverything, h256{}, HeaderData); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; } @@ -824,6 +820,43 @@ LastHashes lastHashes(u256 _currentBlockNumber) return ret; } +dev::eth::Ethash::BlockHeader constructHeader( + h256 const& _parentHash, + h256 const& _sha3Uncles, + Address const& _coinbaseAddress, + h256 const& _stateRoot, + h256 const& _transactionsRoot, + h256 const& _receiptsRoot, + dev::eth::LogBloom const& _logBloom, + u256 const& _difficulty, + u256 const& _number, + u256 const& _gasLimit, + u256 const& _gasUsed, + u256 const& _timestamp, + bytes const& _extraData) +{ + RLPStream rlpStream; + rlpStream.appendList(Ethash::BlockHeader::Fields); + + rlpStream << _parentHash << _sha3Uncles << _coinbaseAddress << _stateRoot << _transactionsRoot << _receiptsRoot << _logBloom + << _difficulty << _number << _gasLimit << _gasUsed << _timestamp << _extraData << h256{} << Nonce{}; + + return Ethash::BlockHeader(rlpStream.out()); +} + +void updateEthashSeal(dev::eth::Ethash::BlockHeader& _header, h256 const& _mixHash, dev::eth::Nonce const& _nonce) +{ + RLPStream source; + _header.streamRLP(source); + RLP sourceRlp(source.out()); + RLPStream header; + header.appendList(Ethash::BlockHeader::Fields); + for (size_t i = 0; i < BlockInfo::BasicFields; i++) + header << sourceRlp[i]; + + header << _mixHash << _nonce; + _header = Ethash::BlockHeader(header.out()); +} namespace { diff --git a/test/TestHelper.h b/test/TestHelper.h index 4ac59e917..735535492 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -27,6 +27,7 @@ #include #include "JsonSpiritHeaders.h" +#include #include #include #include @@ -62,7 +63,7 @@ class State; void mine(Client& c, int numBlocks); void connectClients(Client& c1, Client& c2); void mine(State& _s, BlockChain const& _bc); -void mine(BlockInfo& _bi); +void mine(Ethash::BlockHeader& _bi); } @@ -175,7 +176,21 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o); void checkStorage(std::map _expectedStore, std::map _resultStore, Address _expectedAddr); void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs); void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates); - +dev::eth::Ethash::BlockHeader constructHeader( + h256 const& _parentHash, + h256 const& _sha3Uncles, + Address const& _coinbaseAddress, + h256 const& _stateRoot, + h256 const& _transactionsRoot, + h256 const& _receiptsRoot, + dev::eth::LogBloom const& _logBloom, + u256 const& _difficulty, + u256 const& _number, + u256 const& _gasLimit, + u256 const& _gasUsed, + u256 const& _timestamp, + bytes const& _extraData); +void updateEthashSeal(dev::eth::Ethash::BlockHeader& _header, h256 const& _mixHash, dev::eth::Nonce const& _nonce); void executeTests(const std::string& _name, const std::string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function doTests); void userDefinedTest(std::function doTests); RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj); diff --git a/test/fuzzTesting/checkRandomStateTest.cpp b/test/fuzzTesting/checkRandomStateTest.cpp index 01366cd4d..adbb953f3 100644 --- a/test/fuzzTesting/checkRandomStateTest.cpp +++ b/test/fuzzTesting/checkRandomStateTest.cpp @@ -87,7 +87,7 @@ bool doStateTest(mValue& _v) try { - output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index d533ac2da..be751f2b7 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -233,7 +233,7 @@ void doStateTests(json_spirit::mValue& _v) eth::State theState = importer.m_statePre; try { - output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index c3cd75b0d..0e69793e2 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing, h256{}, HeaderData); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index f9d83e9c6..7c9b7197f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -21,6 +21,7 @@ #include #include +#include #include "../TestUtils.h" using namespace std; @@ -139,7 +140,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); + Ethash::BlockHeader blockInfo((static_cast(_client)).bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index cf44dfd9f..6d4761bb9 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -37,16 +37,17 @@ namespace dev { namespace test { typedef std::vector uncleList; typedef std::pair blockSet; -BlockInfo constructBlock(mObject& _o); -bytes createBlockRLPFromFields(mObject& _tObj); -RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList); +using BlockHeader = Ethash::BlockHeader; + +BlockHeader constructBlock(mObject& _o, h256 const& _stateRoot = h256{}); +bytes createBlockRLPFromFields(mObject& _tObj, h256 const& _stateRoot = h256{}); +RLPStream createFullBlockFromHeader(BlockHeader const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList); mArray writeTransactionsToJson(Transactions const& txs); -mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi); -void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj); -BlockInfo constructBlock(mObject& _o); -void updatePoW(BlockInfo& _bi); -mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); +mObject writeBlockHeaderToJson(mObject& _o, BlockHeader const& _bi); +void overwriteBlockHeader(BlockHeader& _current_BlockHeader, mObject& _blObj); +void updatePoW(BlockHeader& _bi); +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { @@ -61,12 +62,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) cerr << i.first << endl; TBOOST_REQUIRE(o.count("genesisBlockHeader")); - BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj()); TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); + BlockHeader biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj(), h256{}); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path(), h256{}, WithExisting::Kill)), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,7 +77,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot() = trueState.rootHash(); + biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj(), trueState.rootHash()); else TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); @@ -96,7 +97,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // construct true blockchain TransientDirectory td; - BlockChain trueBc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill); + FullBlockChain trueBc(rlpGenesisBlock.out(), StateDefinition(), td.path(), WithExisting::Kill); if (_fillin) { @@ -107,7 +108,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) genesis.first = rlpGenesisBlock.out(); genesis.second = uncleList(); blockSets.push_back(genesis); - vector vBiBlocks; + vector vBiBlocks; vBiBlocks.push_back(biGenesisBlock); size_t importBlockNumber = 0; @@ -124,8 +125,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) vBiBlocks.push_back(biGenesisBlock); TransientDirectory td_stateDB, td_bc; - BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); + FullBlockChain bc(rlpGenesisBlock.out(), StateDefinition(), td_bc.path(), WithExisting::Kill); + State state(OverlayDB(State::openDB(td_stateDB.path(), h256{}, WithExisting::Kill)), BaseState::Empty); + trueState.setAddress(biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -134,12 +136,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) BlockQueue uncleQueue; uncleList uncles = blockSets.at(i).second; for (size_t j = 0; j < uncles.size(); j++) - uncleQueue.import(&uncles.at(j), bc); + uncleQueue.import(&uncles.at(j), false); const bytes block = blockSets.at(i).first; bc.sync(uncleQueue, state.db(), 4); bc.attemptImport(block, state.db()); - vBiBlocks.push_back(BlockInfo(block)); + vBiBlocks.push_back(BlockHeader(block)); state.sync(bc); } @@ -156,7 +158,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } //get uncles - vector vBiUncles; + vector vBiUncles; blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks, blockSets); BlockQueue uncleBlockQueue; @@ -167,7 +169,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) RLPStream uncle = createFullBlockFromHeader(vBiUncles.at(i)); try { - uncleBlockQueue.import(&uncle.out(), bc); + uncleBlockQueue.import(&uncle.out(), false); uncleBlockQueueList.push_back(uncle.out()); // wait until block is verified this_thread::sleep_for(chrono::seconds(1)); @@ -205,14 +207,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) txList.push_back(txi); blObj["transactions"] = writeTransactionsToJson(txList); - BlockInfo current_BlockHeader = state.info(); + BlockHeader current_BlockHeader = state.info(); RLPStream uncleStream; uncleStream.appendList(vBiUncles.size()); for (unsigned i = 0; i < vBiUncles.size(); ++i) { RLPStream uncleRlp; - vBiUncles[i].streamRLP(uncleRlp, WithNonce); + vBiUncles[i].streamRLP(uncleRlp); uncleStream.appendRaw(uncleRlp.out()); } @@ -225,7 +227,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); + current_BlockHeader.setSha3Uncles(sha3(uncleStream.out())); updatePoW(current_BlockHeader); } @@ -330,7 +332,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blockRLP = importByteArray(blObj["rlp"].get_str()); trueState.sync(trueBc); trueBc.import(blockRLP, trueState.db()); - if (trueBc.info() != BlockInfo(blockRLP)) + if (trueBc.info() != BlockHeader(blockRLP)) importedAndBest = false; trueState.sync(trueBc); } @@ -363,17 +365,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(blObj.count("blockHeader")); mObject tObj = blObj["blockHeader"].get_obj(); - BlockInfo blockHeaderFromFields; + BlockHeader blockHeaderFromFields; const bytes c_rlpBytesBlockHeader = createBlockRLPFromFields(tObj); const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader); - blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce); + blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreSeal); - BlockInfo blockFromRlp = trueBc.info(); + BlockHeader blockFromRlp(trueBc.header()); if (importedAndBest) { //Check the fields restored from RLP to original fields - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithProof) == blockFromRlp.headerHash(WithProof)), "hash in given RLP not matching the block hash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); @@ -381,14 +383,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty() == blockFromRlp.difficulty()), "difficulty in given RLP not matching the block difficulty!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number() == blockFromRlp.number()), "number in given RLP not matching the block number!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit() == blockFromRlp.gasLimit()),"gasLimit in given RLP not matching the block gasLimit!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed() == blockFromRlp.gasUsed()), "gasUsed in given RLP not matching the block gasUsed!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash() == blockFromRlp.mixHash()), "mixHash in given RLP not matching the block mixHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce() == blockFromRlp.nonce()), "nonce in given RLP not matching the block nonce!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields == blockFromRlp), "However, blockHeaderFromFields != blockFromRlp!"); @@ -454,7 +456,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // check uncle list // uncles from uncle list field - vector uBlHsFromField; + vector uBlHsFromField; if (blObj["uncleHeaders"].type() != json_spirit::null_type) for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array()) { @@ -462,7 +464,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE((uBlH.size() == 16)); bytes uncleRLP = createBlockRLPFromFields(uBlH); const RLP c_uRLP(uncleRLP); - BlockInfo uncleBlockHeader; + BlockHeader uncleBlockHeader; try { uncleBlockHeader.populateFromHeader(c_uRLP); @@ -475,10 +477,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } // uncles from block RLP - vector uBlHsFromRlp; + vector uBlHsFromRlp; for (auto const& uRLP: root[2]) { - BlockInfo uBl; + BlockHeader uBl; uBl.populateFromHeader(uRLP); uBlHsFromRlp.push_back(uBl); } @@ -499,7 +501,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // helping functions -mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet) +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet) { // write uncle list mArray aUncleList; @@ -521,7 +523,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector { size_t number = (size_t)toInt(uncleHeaderObj["sameAsBlock"]); uncleHeaderObj.erase("sameAsBlock"); - BlockInfo currentUncle = _vBiBlocks[number]; + BlockHeader currentUncle = _vBiBlocks[number]; writeBlockHeaderToJson(uncleHeaderObj, currentUncle); aUncleList.push_back(uncleHeaderObj); _vBiUncles.push_back(currentUncle); @@ -532,7 +534,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector if (uncleHeaderObj.count("sameAsPreviousBlockUncle")) { bytes uncleRLP = _blockSet[(size_t)toInt(uncleHeaderObj["sameAsPreviousBlockUncle"])].second[0]; - BlockInfo uncleHeader(uncleRLP); + BlockHeader uncleHeader(uncleRLP); writeBlockHeaderToJson(uncleHeaderObj, uncleHeader); aUncleList.push_back(uncleHeaderObj); @@ -548,15 +550,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleHeaderObj.erase("overwriteAndRedoPoW"); } - BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); + BlockHeader uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp() = (u256)time(0); - cnote << "uncle block n = " << toString(uncleBlockFromFields.number); + uncleBlockFromFields.setTimestamp((u256)time(0)); + cnote << "uncle block n = " << toString(uncleBlockFromFields.number()); if (_vBiBlocks.size() > 2) { - if (uncleBlockFromFields.number - 1 < _vBiBlocks.size()) - uncleBlockFromFields.populateFromParent(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); + if (uncleBlockFromFields.number() - 1 < _vBiBlocks.size()) + uncleBlockFromFields.populateFromParent(_vBiBlocks[(size_t)uncleBlockFromFields.number() - 1]); else uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 2]); } @@ -565,29 +567,32 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector if (overwrite != "false") { - uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; - uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; - uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); - uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); + uncleBlockFromFields = constructHeader( + overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(), + uncleBlockFromFields.sha3Uncles(), + uncleBlockFromFields.coinbaseAddress(), + overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(), + uncleBlockFromFields.transactionsRoot(), + uncleBlockFromFields.receiptsRoot(), + uncleBlockFromFields.logBloom(), + overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : overwrite == "timestamp" ? uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number() - 1]) : uncleBlockFromFields.difficulty(), + uncleBlockFromFields.number(), + overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit(), + overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed(), + overwrite == "timestamp" ? toInt(uncleHeaderObj["timestamp"]) : uncleBlockFromFields.timestamp(), + uncleBlockFromFields.extraData()); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); - - if (overwrite == "timestamp") - { - uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); - uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); - } } updatePoW(uncleBlockFromFields); if (overwrite == "nonce") - uncleBlockFromFields.nonce = Nonce(uncleHeaderObj["nonce"].get_str()); + updateEthashSeal(uncleBlockFromFields, uncleBlockFromFields.mixHash(), Nonce(uncleHeaderObj["nonce"].get_str())); if (overwrite == "mixHash") - uncleBlockFromFields.mixHash = h256(uncleHeaderObj["mixHash"].get_str()); + updateEthashSeal(uncleBlockFromFields, h256(uncleHeaderObj["mixHash"].get_str()), uncleBlockFromFields.nonce()); writeBlockHeaderToJson(uncleHeaderObj, uncleBlockFromFields); @@ -600,7 +605,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector return aUncleList; } -bytes createBlockRLPFromFields(mObject& _tObj) +bytes createBlockRLPFromFields(mObject& _tObj, h256 const& _stateRoot) { RLPStream rlpStream; rlpStream.appendList(_tObj.count("hash") > 0 ? (_tObj.size() - 1) : _tObj.size()); @@ -614,7 +619,9 @@ bytes createBlockRLPFromFields(mObject& _tObj) if (_tObj.count("coinbase")) rlpStream << importByteArray(_tObj["coinbase"].get_str()); - if (_tObj.count("stateRoot")) + if (_stateRoot) + rlpStream << _stateRoot; + else if (_tObj.count("stateRoot")) rlpStream << importByteArray(_tObj["stateRoot"].get_str()); if (_tObj.count("transactionsTrie")) @@ -653,47 +660,35 @@ bytes createBlockRLPFromFields(mObject& _tObj) return rlpStream.out(); } -void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) +void overwriteBlockHeader(BlockHeader& _header, mObject& _blObj) { auto ho = _blObj["blockHeader"].get_obj(); if (ho.size() != 14) { - BlockInfo tmp = _header; - if (ho.count("parentHash")) - tmp.parentHash() = h256(ho["parentHash"].get_str()); - if (ho.count("uncleHash")) - tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); - if (ho.count("coinbase")) - tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); - if (ho.count("stateRoot")) - tmp.stateRoot() = h256(ho["stateRoot"].get_str()); - if (ho.count("transactionsTrie")) - tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); - if (ho.count("receiptTrie")) - tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); - if (ho.count("bloom")) - tmp.logBloom() = LogBloom(ho["bloom"].get_str()); - if (ho.count("difficulty")) - tmp.difficulty = toInt(ho["difficulty"]); - if (ho.count("number")) - tmp.number = toInt(ho["number"]); - if (ho.count("gasLimit")) - tmp.gasLimit = toInt(ho["gasLimit"]); - if (ho.count("gasUsed")) - tmp.gasUsed = toInt(ho["gasUsed"]); - if (ho.count("timestamp")) - tmp.timestamp() = toInt(ho["timestamp"]); - if (ho.count("extraData")) - tmp.extraData() = importByteArray(ho["extraData"].get_str()); + BlockHeader tmp = constructHeader( + ho.count("parentHash") ? h256(ho["parentHash"].get_str()) : h256{}, + ho.count("uncleHash") ? h256(ho["uncleHash"].get_str()) : EmptyListSHA3, + ho.count("coinbase") ? Address(ho["coinbase"].get_str()) : Address{}, + ho.count("stateRoot") ? h256(ho["stateRoot"].get_str()): h256{}, + ho.count("transactionsTrie") ? h256(ho["transactionsTrie"].get_str()) : EmptyTrie, + ho.count("receiptTrie") ? h256(ho["receiptTrie"].get_str()) : EmptyTrie, + ho.count("bloom") ? LogBloom(ho["bloom"].get_str()) : LogBloom{}, + ho.count("difficulty") ? toInt(ho["difficulty"]) : u256(0), + ho.count("number") ? toInt(ho["number"]) : u256(0), + ho.count("gasLimit") ? toInt(ho["gasLimit"]) : u256(0), + ho.count("gasUsed") ? toInt(ho["gasUsed"]) : u256(0), + ho.count("timestamp") ? toInt(ho["timestamp"]) : u256(0), + ho.count("extraData") ? importByteArray(ho["extraData"].get_str()) : bytes{}); // find new valid nonce - if (tmp != _header && tmp.difficulty) + if (static_cast(tmp) != static_cast(_header) && tmp.difficulty()) mine(tmp); + if (ho.count("mixHash")) - tmp.mixHash = h256(ho["mixHash"].get_str()); + updateEthashSeal(tmp, h256(ho["mixHash"].get_str()), tmp.nonce()); if (ho.count("nonce")) - tmp.nonce = Nonce(ho["nonce"].get_str()); + updateEthashSeal(tmp, tmp.mixHash(), Nonce(ho["nonce"].get_str())); tmp.noteDirty(); _header = tmp; @@ -703,19 +698,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) // take the blockheader as is const bytes c_blockRLP = createBlockRLPFromFields(ho); const RLP c_bRLP(c_blockRLP); - _header.populateFromHeader(c_bRLP, IgnoreNonce); + _header.populateFromHeader(c_bRLP, IgnoreSeal); } } -BlockInfo constructBlock(mObject& _o) +BlockHeader constructBlock(mObject& _o, h256 const& _stateRoot) { - BlockInfo ret; + BlockHeader ret; try { // construct genesis block const bytes c_blockRLP = createBlockRLPFromFields(_o); const RLP c_bRLP(c_blockRLP); - ret.populateFromHeader(c_bRLP, IgnoreNonce); + ret.populateFromHeader(c_bRLP, IgnoreSeal); } catch (Exception const& _e) { @@ -732,7 +727,7 @@ BlockInfo constructBlock(mObject& _o) return ret; } -void updatePoW(BlockInfo& _bi) +void updatePoW(BlockHeader& _bi) { mine(_bi); _bi.noteDirty(); @@ -749,7 +744,7 @@ mArray writeTransactionsToJson(Transactions const& txs) return txArray; } -mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) +mObject writeBlockHeaderToJson(mObject& _o, BlockHeader const& _bi) { _o["parentHash"] = toString(_bi.parentHash()); _o["uncleHash"] = toString(_bi.sha3Uncles()); @@ -758,22 +753,22 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) _o["transactionsTrie"] = toString(_bi.transactionsRoot()); _o["receiptTrie"] = toString(_bi.receiptsRoot()); _o["bloom"] = toString(_bi.logBloom()); - _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); + _o["difficulty"] = toCompactHex(_bi.difficulty(), HexPrefix::Add, 1); _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); - _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); - _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); + _o["gasLimit"] = toCompactHex(_bi.gasLimit(), HexPrefix::Add, 1); + _o["gasUsed"] = toCompactHex(_bi.gasUsed(), HexPrefix::Add, 1); _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); - _o["mixHash"] = toString(_bi.mixHash); - _o["nonce"] = toString(_bi.nonce); + _o["mixHash"] = toString(_bi.mixHash()); + _o["nonce"] = toString(_bi.nonce()); _o["hash"] = toString(_bi.hash()); return _o; } -RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs, bytes const& _uncles) +RLPStream createFullBlockFromHeader(BlockHeader const& _bi, bytes const& _txs, bytes const& _uncles) { RLPStream rlpStream; - _bi.streamRLP(rlpStream, WithNonce); + _bi.streamRLP(rlpStream, WithProof); RLPStream ret(3); ret.appendRaw(rlpStream.out()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 39997572f..a8bc852f0 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hash(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index 45c2fa13e..825ed8b4b 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -63,7 +63,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) try { Listener::ExecTimeGuard guard{i.first}; - output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index badabd70c..36f22734f 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -102,13 +102,26 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash() = h256(_o["previousHash"].get_str()); - currentBlock.number = toInt(_o["currentNumber"]); - lastHashes = test::lastHashes(currentBlock.number); - currentBlock.gasLimit = toInt(_o["currentGasLimit"]); - currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); + + RLPStream rlpStream; + rlpStream.appendList(BlockInfo::BasicFields); + + rlpStream << h256(_o["previousHash"].get_str()); + rlpStream << EmptyListSHA3; + rlpStream << Address(_o["currentCoinbase"].get_str()); + rlpStream << h256(); // stateRoot + rlpStream << EmptyTrie; // transactionTrie + rlpStream << EmptyTrie; // receiptTrie + rlpStream << LogBloom(); // bloom + rlpStream << toInt(_o["currentDifficulty"]); + rlpStream << toInt(_o["currentNumber"]); + rlpStream << toInt(_o["currentGasLimit"]); + rlpStream << 0; //gasUsed + rlpStream << toInt(_o["currentTimestamp"]); + rlpStream << std::string(); //extra data + currentBlock = BlockInfo(rlpStream.out(), CheckEverything, h256{}, HeaderData); + + lastHashes = test::lastHashes(currentBlock.number()); } mObject FakeExtVM::exportState() From 14167c09bfaa5767b53ed2ed45384e60623e8aa5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 18 Jul 2015 16:08:49 +0200 Subject: [PATCH 099/113] fixed ethashcl build --- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 12 ++++++------ libethereum/Client.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 8d5264361..cf3a9820e 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -75,7 +75,7 @@ DEV_SIMPLE_EXCEPTION(NoHashRecorded); * The default constructor creates an empty object, which can be tested against with the boolean * conversion operator. */ -struct BlockInfo +class BlockInfo { friend class BlockChain; public: diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index ee483aa8b..09c6cbe19 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -196,7 +196,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, unsigned, unsigned, unsigned, bool, unsigned, boost::optional) { return false; } + static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: @@ -234,7 +234,7 @@ public: unsigned _deviceId, bool _allowCPU, unsigned _extraGPUMemory, - boost::optional _currentBlock + uint64_t _currentBlock ); static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } @@ -246,7 +246,7 @@ private: void workLoop() override; bool report(uint64_t _nonce); - using Miner::accumulateHashes; + using GenericMiner::accumulateHashes; EthashCLHook* m_hook = nullptr; ethash_cl_miner* m_miner = nullptr; @@ -448,7 +448,7 @@ std::string EthashCPUMiner::platformInfo() class EthashCLHook: public ethash_cl_miner::search_hook { public: - EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {} EthashCLHook(EthashCLHook const&) = delete; void abort() @@ -511,7 +511,7 @@ unsigned EthashGPUMiner::s_deviceId = 0; unsigned EthashGPUMiner::s_numInstances = 0; EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): - Miner(_ci), + GenericMiner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { @@ -527,7 +527,7 @@ EthashGPUMiner::~EthashGPUMiner() bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = EthashAux::eval(work().seedHash, work().headerHash, n); + EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n); if (r.value < work().boundary) return submitProof(Solution{n, r.mixHash}); return false; diff --git a/libethereum/Client.h b/libethereum/Client.h index 4523d324b..18ac1c648 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -337,7 +337,7 @@ public: { m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); m_sealEngine->onSealGenerated([=](bytes const& header){ - return this->submitSealed(header); + this->submitSealed(header); }); init(_host, _dbPath, _forceAction, _networkId); } From f2f234e6cd415d58eb5f81506f6d801c9ac15bca Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jul 2015 18:43:39 +0200 Subject: [PATCH 100/113] Avoid rescuing beyond genesis. Closes #2505 --- libethereum/BlockChain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 8a654fa51..2b6cb25c2 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -849,7 +849,7 @@ void BlockChain::rescue(OverlayDB& _db) u = m; } cout << " lowest is " << l << endl; - for (;; --l) + for (; l > 0; --l) { h256 h = numberHash(l); cout << "Checking validity of " << l << " (" << h << ")..." << flush; From e59a21929ceed677252a88ecb34150b52cec2abd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jul 2015 19:02:59 +0200 Subject: [PATCH 101/113] Build ETHASHCL by default. Closes #2497. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d3c167a..3330977aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ option(GUI "Build GUI components (AlethZero, Mix)" ON) option(TESTS "Build the tests." ON) option(NOBOOST "No use of boost macros in test functions" OFF) option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF) -option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF) +option(ETHASHCL "Build in support for GPU mining via OpenCL" ON) option(JSCONSOLE "Build in javascript console" ON) # propagates CMake configuration options to the compiler From 68fb5e2019e832506aafa7c2ffc224217e0ff560 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Jul 2015 19:15:45 +0200 Subject: [PATCH 102/113] Fix for stateroot in tests. --- test/libethereum/blockchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 6d4761bb9..764585520 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -708,7 +708,7 @@ BlockHeader constructBlock(mObject& _o, h256 const& _stateRoot) try { // construct genesis block - const bytes c_blockRLP = createBlockRLPFromFields(_o); + const bytes c_blockRLP = createBlockRLPFromFields(_o, _stateRoot); const RLP c_bRLP(c_blockRLP); ret.populateFromHeader(c_bRLP, IgnoreSeal); } From c72564d25c695490665b5080a6b49daad20a742c Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 20 Jul 2015 00:36:48 +0200 Subject: [PATCH 103/113] fixing solidity tests --- libethcore/BlockInfo.cpp | 2 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- test/libsolidity/solidityExecutionFramework.h | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 266f57cc8..8e2e2c4c4 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -186,7 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) m_gasLimit = selectGasLimit(_parent); m_gasUsed = 0; m_difficulty = calculateDifficulty(_parent); - m_parentHash = _parent.hash(); + m_parentHash = _parent.m_hash; } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 4a6507cd6..d44545145 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1188,7 +1188,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp() == now && now > 0;\n" + " return block.timestamp == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index f4dbbcb97..0e8637012 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -41,7 +41,11 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } + ExecutionFramework() + { + g_logVerbosity = 0; + m_state.resetCurrent(); + } bytes const& compileAndRunWithoutCheck( std::string const& _sourceCode, From a2df5389405af2cb5c65b2ce1a3a3503cbafcac7 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 20 Jul 2015 08:35:25 +0200 Subject: [PATCH 104/113] opencl.dll copied to alethzero outputs --- alethzero/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 6f9dc59b3..1b1138eab 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -72,5 +72,5 @@ if (SERPENT) endif() # eth_install_executable is defined in cmake/EthExecutableHelper.cmake -eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS EVMJIT_DLLS) +eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS EVMJIT_DLLS OpenCL_DLLS) From 59fad8e6350ad56c1c75545faf15aec76785f7dc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Jul 2015 13:38:40 +0200 Subject: [PATCH 105/113] Actually catch exceptions. --- libethereum/BlockChain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 2b6cb25c2..320797ef3 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -196,7 +196,7 @@ unsigned BlockChain::open(std::string const& _path, WithExisting _we) } } - m_writeOptions.sync = true; +// m_writeOptions.sync = true; if (_we != WithExisting::Verify && !details(m_genesisHash)) { From a552208609af88723b0bf54fcd82ac63ec80634b Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 20 Jul 2015 17:08:59 +0200 Subject: [PATCH 106/113] updated web3 to version 0.9.0 --- libjsqrc/ethereumjs/.versions | 2 +- libjsqrc/ethereumjs/README.md | 52 +- libjsqrc/ethereumjs/bower.json | 2 +- libjsqrc/ethereumjs/dist/web3-light.js | 537 ++++- libjsqrc/ethereumjs/dist/web3-light.min.js | 5 +- libjsqrc/ethereumjs/dist/web3.js | 537 ++++- libjsqrc/ethereumjs/dist/web3.js.map | 34 +- libjsqrc/ethereumjs/dist/web3.min.js | 6 +- libjsqrc/ethereumjs/example/balance.html | 2 +- libjsqrc/ethereumjs/example/contract.html | 21 +- .../ethereumjs/example/contract_array.html | 22 +- libjsqrc/ethereumjs/example/event_inc.html | 28 +- libjsqrc/ethereumjs/index.js | 4 +- libjsqrc/ethereumjs/lib/version.json | 2 +- libjsqrc/ethereumjs/lib/web3.js | 3 + libjsqrc/ethereumjs/lib/web3/allevents.js | 1 - libjsqrc/ethereumjs/lib/web3/batch.js | 11 +- libjsqrc/ethereumjs/lib/web3/contract.js | 125 +- libjsqrc/ethereumjs/lib/web3/errors.js | 2 +- libjsqrc/ethereumjs/lib/web3/eth.js | 16 + libjsqrc/ethereumjs/lib/web3/event.js | 2 +- libjsqrc/ethereumjs/lib/web3/filter.js | 8 +- libjsqrc/ethereumjs/lib/web3/formatters.js | 33 +- libjsqrc/ethereumjs/lib/web3/httpprovider.js | 26 +- libjsqrc/ethereumjs/lib/web3/ipcprovider.js | 211 ++ libjsqrc/ethereumjs/lib/web3/method.js | 2 +- libjsqrc/ethereumjs/lib/web3/property.js | 36 +- libjsqrc/ethereumjs/lib/web3/qtsync.js | 33 - libjsqrc/ethereumjs/package.js | 2 +- libjsqrc/ethereumjs/package.json | 22 +- libjsqrc/ethereumjs/styleguide.md | 1741 +++++++++++++++++ libjsqrc/ethereumjs/test/batch.js | 98 +- libjsqrc/ethereumjs/test/contract.js | 8 +- libjsqrc/ethereumjs/test/errors.js | 17 + libjsqrc/ethereumjs/test/event.encode.js | 2 + .../test/helpers/FakeHttpProvider.js | 22 +- .../ethereumjs/test/helpers/FakeIpcRequest.js | 41 + libjsqrc/ethereumjs/test/httpprovider.js | 8 + libjsqrc/ethereumjs/test/ipcprovider.js | 58 + libjsqrc/ethereumjs/test/polling.js | 2 - libjsqrc/ethereumjs/test/qtsyncprovider.js | 22 - libjsqrc/ethereumjs/test/web3.eth.contract.js | 22 +- .../test/web3.eth.getTransaction.js | 2 - .../test/web3.eth.getTransactionReceipt.js | 70 + 44 files changed, 3507 insertions(+), 393 deletions(-) create mode 100644 libjsqrc/ethereumjs/lib/web3/ipcprovider.js delete mode 100644 libjsqrc/ethereumjs/lib/web3/qtsync.js create mode 100644 libjsqrc/ethereumjs/styleguide.md create mode 100644 libjsqrc/ethereumjs/test/errors.js create mode 100644 libjsqrc/ethereumjs/test/helpers/FakeIpcRequest.js create mode 100644 libjsqrc/ethereumjs/test/ipcprovider.js delete mode 100644 libjsqrc/ethereumjs/test/qtsyncprovider.js create mode 100644 libjsqrc/ethereumjs/test/web3.eth.getTransactionReceipt.js diff --git a/libjsqrc/ethereumjs/.versions b/libjsqrc/ethereumjs/.versions index f8cf2429e..836261f72 100644 --- a/libjsqrc/ethereumjs/.versions +++ b/libjsqrc/ethereumjs/.versions @@ -1,3 +1,3 @@ -ethereum:web3@0.5.0 +ethereum:web3@0.7.0 meteor@1.1.6 underscore@1.0.3 diff --git a/libjsqrc/ethereumjs/README.md b/libjsqrc/ethereumjs/README.md index 8abd8821d..ebf6749bd 100644 --- a/libjsqrc/ethereumjs/README.md +++ b/libjsqrc/ethereumjs/README.md @@ -17,42 +17,52 @@ You need to run a local ethrereum node to use this library. ### Node.js - $ npm install web3 +```bash +npm install web3 +``` ### Meteor.js - $ meteor add ethereum:web3 +```bash +meteor add ethereum:web3 +``` ### As Browser module Bower - $ bower install web3 +```bash +bower install web3 +``` Component - $ component install ethereum/web3.js +```bash +component install ethereum/web3.js +``` * Include `ethereum.min.js` in your html file. (not required for the meteor package) -* Include [bignumber.js](https://github.com/MikeMcl/bignumber.js/) (not required for the meteor package) ## Usage Use the `web3` object directly from global namespace: - console.log(web3); // {eth: .., shh: ...} // it's here! +```js +console.log(web3); // {eth: .., shh: ...} // it's here! +``` -Set a provider (QtSyncProvider, HttpProvider) +Set a provider (HttpProvider) - web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545')); +```js +web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545')); +``` There you go, now you can use it: -``` +```js var coinbase = web3.eth.coinbase; var balance = web3.eth.getBalance(coinbase); ``` - -For another example see `example/index.html`. +You can find more examples in [`example`](https://github.com/ethereum/web3.js/tree/master/example) directory. ## Contribute! @@ -82,26 +92,6 @@ npm run-script build npm test ``` -### Testing (karma) -Karma allows testing within one or several browsers. - -```bash -npm run-script karma # default browsers are Chrome and Firefox -npm run-script karma -- --browsers="Chrome,Safari" # custom browsers -``` - - -**Please note this repo is in it's early stage.** - -If you'd like to run a Http ethereum node check out -[cpp-ethereum](https://github.com/ethereum/cpp-ethereum). - -Install ethereum and spawn a node: - -``` -eth -j -``` - [npm-image]: https://badge.fury.io/js/web3.png [npm-url]: https://npmjs.org/package/web3 [travis-image]: https://travis-ci.org/ethereum/web3.js.svg diff --git a/libjsqrc/ethereumjs/bower.json b/libjsqrc/ethereumjs/bower.json index fb38bda61..6fd61ec3e 100644 --- a/libjsqrc/ethereumjs/bower.json +++ b/libjsqrc/ethereumjs/bower.json @@ -1,7 +1,7 @@ { "name": "web3", "namespace": "ethereum", - "version": "0.7.1", + "version": "0.9.0", "description": "Ethereum Compatible JavaScript API", "main": [ "./dist/web3.js", diff --git a/libjsqrc/ethereumjs/dist/web3-light.js b/libjsqrc/ethereumjs/dist/web3-light.js index f939d164b..b4f00e798 100644 --- a/libjsqrc/ethereumjs/dist/web3-light.js +++ b/libjsqrc/ethereumjs/dist/web3-light.js @@ -1398,7 +1398,7 @@ module.exports = { },{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){ module.exports={ - "version": "0.7.1" + "version": "0.9.0" } },{}],9:[function(require,module,exports){ @@ -1505,6 +1505,9 @@ web3.setProvider = function (provider) { this.currentProvider = provider; RequestManager.getInstance().setProvider(provider); }; +web3.isConnected = function(){ + return (this.currentProvider && this.currentProvider.isConnected()); +}; web3.reset = function () { RequestManager.getInstance().reset(); c.defaultBlock = 'latest'; @@ -1575,7 +1578,7 @@ setupMethods(web3.shh, shh.methods); module.exports = web3; -},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":23,"./web3/net":25,"./web3/property":26,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){ +},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":24,"./web3/net":26,"./web3/property":27,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1620,7 +1623,6 @@ AllSolidityEvents.prototype.encode = function (options) { result[f] = formatters.inputBlockNumberFormatter(options[f]); }); - result.topics = [null, null, null, null, null]; // match all topics result.address = this._address; return result; @@ -1682,6 +1684,8 @@ module.exports = AllSolidityEvents; */ var RequestManager = require('./requestmanager'); +var Jsonrpc = require('./jsonrpc'); +var errors = require('./errors'); var Batch = function () { this.requests = []; @@ -1708,11 +1712,14 @@ Batch.prototype.execute = function () { results = results || []; requests.map(function (request, index) { return results[index] || {}; - }).map(function (result, index) { - return requests[index].format ? requests[index].format(result.result) : result.result; }).forEach(function (result, index) { if (requests[index].callback) { - requests[index].callback(err, result); + + if (!Jsonrpc.getInstance().isValidResponse(result)) { + return requests[index].callback(errors.InvalidResponse(result)); + } + + requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result)); } }); }); @@ -1721,7 +1728,7 @@ Batch.prototype.execute = function () { module.exports = Batch; -},{"./requestmanager":28}],12:[function(require,module,exports){ +},{"./errors":14,"./jsonrpc":23,"./requestmanager":28}],12:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1820,6 +1827,79 @@ var contract = function (abi) { return new ContractFactory(abi); }; +/** + * Should be called to check if the contract gets properly deployed on the blockchain. + * + * @method checkForContractAddress + * @param {Object} contract + * @param {Function} callback + * @returns {Undefined} + */ +var checkForContractAddress = function(contract, abi, callback){ + var count = 0, + callbackFired = false; + + // wait for receipt + var filter = web3.eth.filter('latest', function(e){ + if(!e && !callbackFired) { + count++; + + // console.log('Checking for contract address', count); + + // stop watching after 50 blocks (timeout) + if(count > 50) { + + filter.stopWatching(); + callbackFired = true; + + if(callback) + callback(new Error('Contract transaction couldn\'t be found after 50 blocks')); + else + throw new Error('Contract transaction couldn\'t be found after 50 blocks'); + + + } else { + + web3.eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){ + if(receipt && !callbackFired) { + + web3.eth.getCode(receipt.contractAddress, function(e, code){ + /*jshint maxcomplexity: 5 */ + + if(callbackFired) + return; + + filter.stopWatching(); + callbackFired = true; + + if(code.length > 2) { + + // console.log('Contract code deployed!'); + + contract.address = receipt.contractAddress; + + // attach events and methods + addFunctionsToContract(contract, abi); + addEventsToContract(contract, abi); + + // call callback for the second time + if(callback) + callback(null, contract); + + } else { + if(callback) + callback(new Error('The contract code couldn\'t be stored, please check your gas amount.')); + else + throw new Error('The contract code couldn\'t be stored, please check your gas amount.'); + } + }); + } + }); + } + } + }); +}; + /** * Should be called to create new ContractFactory instance * @@ -1838,10 +1918,12 @@ var ContractFactory = function (abi) { * @param {Any} contract constructor param2 (optional) * @param {Object} contract transaction object (required) * @param {Function} callback - * @returns {Contract} returns contract if no callback was passed, - * otherwise calls callback function (err, contract) + * @returns {Contract} returns contract instance */ ContractFactory.prototype.new = function () { + var _this = this; + var contract = new Contract(this.abi); + // parse arguments var options = {}; // required! var callback; @@ -1861,18 +1943,31 @@ ContractFactory.prototype.new = function () { var bytes = encodeConstructorParams(this.abi, args); options.data += bytes; - if (!callback) { - var address = web3.eth.sendTransaction(options); - return this.at(address); + + if(callback) { + + // wait for the contract address adn check if the code was deployed + web3.eth.sendTransaction(options, function (err, hash) { + if (err) { + callback(err); + } else { + // add the transaction hash + contract.transactionHash = hash; + + // call callback for the first time + callback(null, contract); + + checkForContractAddress(contract, _this.abi, callback); + } + }); + } else { + var hash = web3.eth.sendTransaction(options); + // add the transaction hash + contract.transactionHash = hash; + checkForContractAddress(contract, _this.abi); } - - var self = this; - web3.eth.sendTransaction(options, function (err, address) { - if (err) { - callback(err); - } - self.at(address, callback); - }); + + return contract; }; /** @@ -1885,12 +1980,17 @@ ContractFactory.prototype.new = function () { * otherwise calls callback function (err, contract) */ ContractFactory.prototype.at = function (address, callback) { + var contract = new Contract(this.abi, address); // TODO: address is required + + // attach functions + addFunctionsToContract(contract, this.abi); + addEventsToContract(contract, this.abi); if (callback) { - callback(null, new Contract(this.abi, address)); + callback(null, contract); } - return new Contract(this.abi, address); + return contract; }; /** @@ -1902,8 +2002,6 @@ ContractFactory.prototype.at = function (address, callback) { */ var Contract = function (abi, address) { this.address = address; - addFunctionsToContract(this, abi); - addEventsToContract(this, abi); }; module.exports = contract; @@ -1967,7 +2065,7 @@ module.exports = { methods: methods }; -},{"./method":23}],14:[function(require,module,exports){ +},{"./method":24}],14:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2001,7 +2099,7 @@ module.exports = { return new Error('Providor not set or invalid'); }, InvalidResponse: function (result){ - var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response'; + var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: '+ result; return new Error(message); } }; @@ -2162,6 +2260,13 @@ var getTransactionFromBlock = new Method({ outputFormatter: formatters.outputTransactionFormatter }); +var getTransactionReceipt = new Method({ + name: 'getTransactionReceipt', + call: 'eth_getTransactionReceipt', + params: 1, + outputFormatter: formatters.outputTransactionReceiptFormatter +}); + var getTransactionCount = new Method({ name: 'getTransactionCount', call: 'eth_getTransactionCount', @@ -2174,7 +2279,7 @@ var sendRawTransaction = new Method({ name: 'sendRawTransaction', call: 'eth_sendRawTransaction', params: 1, - inputFormatter: [] + inputFormatter: [null] }); var sendTransaction = new Method({ @@ -2240,6 +2345,7 @@ var methods = [ getBlockUncleCount, getTransaction, getTransactionFromBlock, + getTransactionReceipt, getTransactionCount, call, estimateGas, @@ -2292,7 +2398,7 @@ module.exports = { }; -},{"../utils/utils":7,"./formatters":18,"./method":23,"./property":26}],16:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":18,"./method":24,"./property":27}],16:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2398,8 +2504,8 @@ SolidityEvent.prototype.encode = function (indexed, options) { result.topics = []; + result.address = this._address; if (!this._anonymous) { - result.address = this._address; result.topics.push('0x' + this.signature()); } @@ -2594,9 +2700,11 @@ var getLogsAtStart = function(self, callback){ callback(err); } - messages.forEach(function (message) { - callback(null, message); - }); + if(utils.isArray(messages)) { + messages.forEach(function (message) { + callback(null, message); + }); + } }); } }; @@ -2798,8 +2906,8 @@ var inputTransactionFormatter = function (options){ * Formats the output of a transaction to its proper values * * @method outputTransactionFormatter - * @param {Object} transaction - * @returns {Object} transaction + * @param {Object} tx + * @returns {Object} */ var outputTransactionFormatter = function (tx){ if(tx.blockNumber !== null) @@ -2813,12 +2921,36 @@ var outputTransactionFormatter = function (tx){ return tx; }; +/** + * Formats the output of a transaction receipt to its proper values + * + * @method outputTransactionReceiptFormatter + * @param {Object} receipt + * @returns {Object} +*/ +var outputTransactionReceiptFormatter = function (receipt){ + if(receipt.blockNumber !== null) + receipt.blockNumber = utils.toDecimal(receipt.blockNumber); + if(receipt.transactionIndex !== null) + receipt.transactionIndex = utils.toDecimal(receipt.transactionIndex); + receipt.cumulativeGasUsed = utils.toDecimal(receipt.cumulativeGasUsed); + receipt.gasUsed = utils.toDecimal(receipt.gasUsed); + + if(utils.isArray(receipt.logs)) { + receipt.logs = receipt.logs.map(function(log){ + return outputLogFormatter(log); + }); + } + + return receipt; +}; + /** * Formats the output of a block to its proper values * * @method outputBlockFormatter - * @param {Object} block object - * @returns {Object} block object + * @param {Object} block + * @returns {Object} */ var outputBlockFormatter = function(block) { @@ -2926,6 +3058,7 @@ module.exports = { inputPostFormatter: inputPostFormatter, outputBigNumberFormatter: outputBigNumberFormatter, outputTransactionFormatter: outputTransactionFormatter, + outputTransactionReceiptFormatter: outputTransactionReceiptFormatter, outputBlockFormatter: outputBlockFormatter, outputLogFormatter: outputLogFormatter, outputPostFormatter: outputPostFormatter @@ -3191,12 +3324,11 @@ module.exports = SolidityFunction; * Marek Kotewicz * Marian Oancea * Fabian Vogelsteller - * @date 2014 + * @date 2015 */ "use strict"; -// resolves the problem for electron/atom shell environments, which use node integration, but have no process variable available var XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line var errors = require('./errors'); @@ -3204,6 +3336,25 @@ var HttpProvider = function (host) { this.host = host || 'http://localhost:8545'; }; +HttpProvider.prototype.isConnected = function() { + var request = new XMLHttpRequest(); + + request.open('POST', this.host, false); + request.setRequestHeader('Content-type','application/json'); + + try { + request.send(JSON.stringify({ + id: 9999999999, + jsonrpc: '2.0', + method: 'net_listening', + params: [] + })); + return true; + } catch(e) { + return false; + } +}; + HttpProvider.prototype.send = function (payload) { var request = new XMLHttpRequest(); @@ -3228,7 +3379,7 @@ HttpProvider.prototype.send = function (payload) { try { result = JSON.parse(result); } catch(e) { - throw errors.InvalidResponse(result); + throw errors.InvalidResponse(request.responseText); } return result; @@ -3244,7 +3395,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { try { result = JSON.parse(result); } catch(e) { - error = errors.InvalidResponse(result); + error = errors.InvalidResponse(request.responseText); } callback(error, result); @@ -3391,6 +3542,219 @@ module.exports = ICAP; You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ +/** @file ipcprovider.js + * @authors: + * Fabian Vogelsteller + * @date 2015 + */ + +"use strict"; + +var utils = require('../utils/utils'); +var errors = require('./errors'); + +var errorTimeout = '{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}'; + + +var IpcProvider = function (path, net) { + var _this = this; + this.responseCallbacks = {}; + this.path = path; + + net = net || require('net'); + + this.connection = net.connect({path: this.path}); + + this.connection.on('error', function(e){ + console.error('IPC Connection Error', e); + _this._timeout(); + }); + + this.connection.on('end', function(){ + _this._timeout(); + }); + + + // LISTEN FOR CONNECTION RESPONSES + this.connection.on('data', function(data) { + /*jshint maxcomplexity: 6 */ + + _this._parseResponse(data.toString()).forEach(function(result){ + + var id = null; + + // get the id which matches the returned id + if(utils.isArray(result)) { + result.forEach(function(load){ + if(_this.responseCallbacks[load.id]) + id = load.id; + }); + } else { + id = result.id; + } + + // fire the callback + if(_this.responseCallbacks[id]) { + _this.responseCallbacks[id](null, result); + delete _this.responseCallbacks[id]; + } + }); + }); +}; + +/** +Will parse the response and make an array out of it. + +@method _parseResponse +@param {String} data +*/ +IpcProvider.prototype._parseResponse = function(data) { + var _this = this, + returnValues = []; + + // DE-CHUNKER + var dechunkedData = data + .replace(/\}\{/g,'}|--|{') // }{ + .replace(/\}\]\[\{/g,'}]|--|[{') // }][{ + .replace(/\}\[\{/g,'}|--|[{') // }[{ + .replace(/\}\]\{/g,'}]|--|{') // }]{ + .split('|--|'); + + dechunkedData.forEach(function(data){ + + // prepend the last chunk + if(_this.lastChunk) + data = _this.lastChunk + data; + + var result = null; + + try { + result = JSON.parse(data); + + } catch(e) { + + _this.lastChunk = data; + + // start timeout to cancel all requests + clearTimeout(_this.lastChunkTimeout); + _this.lastChunkTimeout = setTimeout(function(){ + _this.timeout(); + throw errors.InvalidResponse(data); + }, 1000 * 15); + + return; + } + + // cancel timeout and set chunk to null + clearTimeout(_this.lastChunkTimeout); + _this.lastChunk = null; + + if(result) + returnValues.push(result); + }); + + return returnValues; +}; + + +/** +Get the adds a callback to the responseCallbacks object, +which will be called if a response matching the response Id will arrive. + +@method _addResponseCallback +*/ +IpcProvider.prototype._addResponseCallback = function(payload, callback) { + var id = payload.id || payload[0].id; + var method = payload.method || payload[0].method; + + this.responseCallbacks[id] = callback; + this.responseCallbacks[id].method = method; +}; + +/** +Timeout all requests when the end/error event is fired + +@method _timeout +*/ +IpcProvider.prototype._timeout = function() { + for(var key in this.responseCallbacks) { + if(this.responseCallbacks.hasOwnProperty(key)){ + this.responseCallbacks[key](errorTimeout.replace('__id__', key).replace('__method__', this.responseCallbacks[key].method)); + delete this.responseCallbacks[key]; + } + } +}; + + +/** +Check if the current connection is still valid. + +@method isConnected +*/ +IpcProvider.prototype.isConnected = function() { + var _this = this; + + // try reconnect, when connection is gone + if(!_this.connection.writable) + _this.connection.connect({path: _this.path}); + + return !!this.connection.writable; +}; + +IpcProvider.prototype.send = function (payload) { + + if(this.connection.writeSync) { + var result; + + // try reconnect, when connection is gone + if(!this.connection.writable) + this.connection.connect({path: this.path}); + + var data = this.connection.writeSync(JSON.stringify(payload)); + + try { + result = JSON.parse(data); + } catch(e) { + throw errors.InvalidResponse(data); + } + + return result; + + } else { + throw new Error('You tried to send "'+ payload.method +'" synchronously. Synchronous requests are not supported by the IPC provider.'); + } +}; + +IpcProvider.prototype.sendAsync = function (payload, callback) { + // try reconnect, when connection is gone + if(!this.connection.writable) + this.connection.connect({path: this.path}); + + + this.connection.write(JSON.stringify(payload)); + this._addResponseCallback(payload, callback); +}; + +module.exports = IpcProvider; + + +},{"../utils/utils":7,"./errors":14,"net":32}],23:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ /** @file jsonrpc.js * @authors: * Marek Kotewicz @@ -3467,7 +3831,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) { module.exports = Jsonrpc; -},{}],23:[function(require,module,exports){ +},{}],24:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3564,7 +3928,7 @@ Method.prototype.formatInput = function (args) { * @return {Object} */ Method.prototype.formatOutput = function (result) { - return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; + return this.outputFormatter && result ? this.outputFormatter(result) : result; }; /** @@ -3641,7 +4005,7 @@ Method.prototype.send = function () { module.exports = Method; -},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],24:[function(require,module,exports){ +},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],25:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3689,7 +4053,7 @@ var abi = [ module.exports = contract(abi).at(address); -},{"./contract":12}],25:[function(require,module,exports){ +},{"./contract":12}],26:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3739,7 +4103,7 @@ module.exports = { }; -},{"../utils/utils":7,"./property":26}],26:[function(require,module,exports){ +},{"../utils/utils":7,"./property":27}],27:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3764,6 +4128,7 @@ module.exports = { */ var RequestManager = require('./requestmanager'); +var utils = require('../utils/utils'); var Property = function (options) { this.name = options.name; @@ -3795,6 +4160,19 @@ Property.prototype.formatOutput = function (result) { return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; }; +/** + * Should be used to extract callback from array of arguments. Modifies input param + * + * @method extractCallback + * @param {Array} arguments + * @return {Function|Null} callback, if exists + */ +Property.prototype.extractCallback = function (args) { + if (utils.isFunction(args[args.length - 1])) { + return args.pop(); // modify the args array! + } +}; + /** * Should attach function to method * @@ -3821,7 +4199,10 @@ Property.prototype.attachToObject = function (obj) { return prefix + name.charAt(0).toUpperCase() + name.slice(1); }; - obj[toAsyncName('get', name)] = this.getAsync.bind(this); + var func = this.getAsync.bind(this); + func.request = this.request.bind(this); + + obj[toAsyncName('get', name)] = func; }; /** @@ -3854,45 +4235,27 @@ Property.prototype.getAsync = function (callback) { }); }; -module.exports = Property; - - -},{"./requestmanager":28}],27:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file qtsync.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * @date 2014 +/** + * Should be called to create pure JSONRPC request which can be used in batch request + * + * @method request + * @param {...} params + * @return {Object} jsonrpc request */ - -var QtSyncProvider = function () { -}; - -QtSyncProvider.prototype.send = function (payload) { - var result = navigator.qt.callMethod(JSON.stringify(payload)); - return JSON.parse(result); +Property.prototype.request = function () { + var payload = { + method: this.getter, + params: [], + callback: this.extractCallback(Array.prototype.slice.call(arguments)) + }; + payload.format = this.formatOutput.bind(this); + return payload; }; -module.exports = QtSyncProvider; +module.exports = Property; -},{}],28:[function(require,module,exports){ +},{"../utils/utils":7,"./requestmanager":28}],28:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -4157,7 +4520,7 @@ RequestManager.prototype.poll = function () { module.exports = RequestManager; -},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":22}],29:[function(require,module,exports){ +},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":23}],29:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -4227,7 +4590,7 @@ module.exports = { }; -},{"./formatters":18,"./method":23}],30:[function(require,module,exports){ +},{"./formatters":18,"./method":24}],30:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -4323,7 +4686,7 @@ var deposit = function (from, address, value, client, callback) { module.exports = transfer; -},{"../web3":9,"./contract":12,"./icap":21,"./namereg":24}],31:[function(require,module,exports){ +},{"../web3":9,"./contract":12,"./icap":21,"./namereg":25}],31:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -4439,7 +4802,7 @@ module.exports = { }; -},{"./method":23}],32:[function(require,module,exports){ +},{"./method":24}],32:[function(require,module,exports){ },{}],33:[function(require,module,exports){ ;(function (root, factory) { @@ -5821,8 +6184,10 @@ module.exports = BigNumber; // jshint ignore:line },{}],"web3":[function(require,module,exports){ var web3 = require('./lib/web3'); + web3.providers.HttpProvider = require('./lib/web3/httpprovider'); -web3.providers.QtSyncProvider = require('./lib/web3/qtsync'); +web3.providers.IpcProvider = require('./lib/web3/ipcprovider'); + web3.eth.contract = require('./lib/web3/contract'); web3.eth.namereg = require('./lib/web3/namereg'); web3.eth.sendIBANTransaction = require('./lib/web3/transfer'); @@ -5835,5 +6200,5 @@ if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { module.exports = web3; -},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/namereg":24,"./lib/web3/qtsync":27,"./lib/web3/transfer":30}]},{},["web3"]) +},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/ipcprovider":22,"./lib/web3/namereg":25,"./lib/web3/transfer":30}]},{},["web3"]) //# sourceMappingURL=web3-light.js.map diff --git a/libjsqrc/ethereumjs/dist/web3-light.min.js b/libjsqrc/ethereumjs/dist/web3-light.min.js index 9907881ad..65b2bf23f 100644 --- a/libjsqrc/ethereumjs/dist/web3-light.min.js +++ b/libjsqrc/ethereumjs/dist/web3-light.min.js @@ -1,2 +1,3 @@ -require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ai;i+=64)n.push(this._outputFormatter(new a(t.dynamicPart().substr(i+64,64))));return n}return this._outputFormatter(t)},u.prototype.sliceParam=function(t,e,n){return"bytes"===this._mode?a.decodeBytes(t,e):s(n)?a.decodeArray(t,e):a.decodeParam(t,e)};var c=function(t){this._types=t};c.prototype._requireType=function(t){var e=this._types.filter(function(e){return e.isType(t)})[0];if(!e)throw Error("invalid solidity type!: "+t);return e},c.prototype._formatInput=function(t,e){return this._requireType(t).formatInput(e,s(t))},c.prototype.encodeParam=function(t,e){return this._formatInput(t,e).encode()},c.prototype.encodeParams=function(t,e){var n=this,r=t.map(function(t,r){return n._formatInput(t,e[r])});return a.encodeList(r)},c.prototype.decodeParam=function(t,e){return this.decodeParams([t],e)[0]},c.prototype.decodeParams=function(t,e){var n=this;return t.map(function(t,r){var o=n._requireType(t),i=o.sliceParam(e,r,t);return o.formatOutput(i,s(t))})};var l=new c([new u({name:"address",match:"strict",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputAddress}),new u({name:"bool",match:"strict",mode:"value",inputFormatter:i.formatInputBool,outputFormatter:i.formatOutputBool}),new u({name:"int",match:"prefix",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputInt}),new u({name:"uint",match:"prefix",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputUInt}),new u({name:"bytes",match:"strict",mode:"bytes",inputFormatter:i.formatInputDynamicBytes,outputFormatter:i.formatOutputDynamicBytes}),new u({name:"bytes",match:"prefix",mode:"value",inputFormatter:i.formatInputBytes,outputFormatter:i.formatOutputBytes}),new u({name:"string",match:"strict",mode:"bytes",inputFormatter:i.formatInputString,outputFormatter:i.formatOutputString}),new u({name:"real",match:"prefix",mode:"value",inputFormatter:i.formatInputReal,outputFormatter:i.formatOutputReal}),new u({name:"ureal",match:"prefix",mode:"value",inputFormatter:i.formatInputReal,outputFormatter:i.formatOutputUReal})]);e.exports=l},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(t,e,n){var r=t("bignumber.js"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./param"),s=function(t){var e=2*i.ETH_PADDING;r.config(i.ETH_BIGNUMBER_ROUNDING_MODE);var n=o.padLeft(o.toTwosComplement(t).round().toString(16),e);return new a(n)},u=function(t){var e=o.padRight(o.toHex(t).substr(2),64);return new a(e)},c=function(t){t=o.toHex(t).substr(2);var e=Math.floor((t.length+63)/64),n=o.padRight(t,64*e),r=Math.floor(t.length/2);return new a(s(r).value+n,32)},l=function(t){var e=o.fromAscii(t).substr(2),n=Math.floor((e.length+63)/64);return e=o.padRight(e,64*n),new a(s(t.length).value+e,32)},p=function(t){var e="000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0");return new a(e)},f=function(t){return s(new r(t).times(new r(2).pow(128)))},m=function(t){return"1"===new r(t.substr(0,1),16).toString(2).substr(0,1)},h=function(t){var e=t.staticPart()||"0";return m(e)?new r(e,16).minus(new r("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new r(e,16)},d=function(t){var e=t.staticPart()||"0";return new r(e,16)},y=function(t){return h(t).dividedBy(new r(2).pow(128))},g=function(t){return d(t).dividedBy(new r(2).pow(128))},v=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t.staticPart()?!0:!1},b=function(t){return"0x"+t.staticPart()},w=function(t){var e=2*new r(t.dynamicPart().slice(0,64),16).toNumber();return"0x"+t.dynamicPart().substr(64,e)},_=function(t){var e=2*new r(t.dynamicPart().slice(0,64),16).toNumber();return o.toAscii(t.dynamicPart().substr(64,e))},x=function(t){var e=t.staticPart();return"0x"+e.slice(e.length-40,e.length)};e.exports={formatInputInt:s,formatInputBytes:u,formatInputDynamicBytes:c,formatInputString:l,formatInputBool:p,formatInputReal:f,formatOutputInt:h,formatOutputUInt:d,formatOutputReal:y,formatOutputUReal:g,formatOutputBool:v,formatOutputBytes:b,formatOutputDynamicBytes:w,formatOutputString:_,formatOutputAddress:x}},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),o=function(t,e){this.value=t||"",this.offset=e};o.prototype.dynamicPartLength=function(){return this.dynamicPart().length/2},o.prototype.withOffset=function(t){return new o(this.value,t)},o.prototype.combine=function(t){return new o(this.value+t.value)},o.prototype.isDynamic=function(){return this.value.length>64||void 0!==this.offset},o.prototype.offsetAsBytes=function(){return this.isDynamic()?r.padLeft(r.toTwosComplement(this.offset).toString(16),64):""},o.prototype.staticPart=function(){return this.isDynamic()?this.offsetAsBytes():this.value},o.prototype.dynamicPart=function(){return this.isDynamic()?this.value:""},o.prototype.encode=function(){return this.staticPart()+this.dynamicPart()},o.encodeList=function(t){var e=32*t.length,n=t.map(function(t){if(!t.isDynamic())return t;var n=e;return e+=t.dynamicPartLength(),t.withOffset(n)});return n.reduce(function(t,e){return t+e.dynamicPart()},n.reduce(function(t,e){return t+e.staticPart()},""))},o.decodeParam=function(t,e){return e=e||0,new o(t.substr(64*e,64))};var i=function(t,e){return parseInt("0x"+t.substr(64*e,64))};o.decodeBytes=function(t,e){e=e||0;var n=i(t,e),r=parseInt("0x"+t.substr(2*n,64));return r=Math.floor((r+31)/32),new o(t.substr(2*n,64*(1+r)),0)},o.decodeArray=function(t,e){e=e||0;var n=i(t,e),r=parseInt("0x"+t.substr(2*n,64));return new o(t.substr(2*n,64*(r+1)),0)},e.exports=o},{"../utils/utils":7}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e,n){var r=t("bignumber.js"),o=["wei","kwei","Mwei","Gwei","szabo","finney","femtoether","picoether","nanoether","microether","milliether","nano","micro","milli","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:o,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:r.ROUND_DOWN},ETH_POLLING_TIMEOUT:500,defaultBlock:"latest",defaultAccount:void 0}},{"bignumber.js":"bignumber.js"}],6:[function(t,e,n){var r=t("./utils"),o=t("crypto-js/sha3");e.exports=function(t,e){return"0x"!==t.substr(0,2)||e||(console.warn("requirement of using web3.fromAscii before sha3 is deprecated"),console.warn("new usage: 'web3.sha3(\"hello\")'"),console.warn("see https://github.com/ethereum/web3.js/pull/205"),console.warn("if you need to hash hex value, you can do 'sha3(\"0xfff\", true)'"),t=r.toAscii(t)),o(t,{outputLength:256}).toString()}},{"./utils":7,"crypto-js/sha3":34}],7:[function(t,e,n){var r=t("bignumber.js"),o={wei:"1",kwei:"1000",ada:"1000",femtoether:"1000",mwei:"1000000",babbage:"1000000",picoether:"1000000",gwei:"1000000000",shannon:"1000000000",nanoether:"1000000000",nano:"1000000000",szabo:"1000000000000",microether:"1000000000000",micro:"1000000000000",finney:"1000000000000000",milliether:"1000000000000000",milli:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},i=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t,e,n){return t+new Array(e-t.length+1).join(n?n:"0")},s=function(t){var e="",n=0,r=t.length;for("0x"===t.substring(0,2)&&(n=2);r>n;n+=2){var o=parseInt(t.substr(n,2),16);e+=String.fromCharCode(o)}return e},u=function(t){for(var e="",n=0;n0&&c(o),r)return o.watch(r)})};l.prototype.watch=function(t){return this.callbacks.push(t),this.filterId&&(u(this,t),c(this)),this},l.prototype.stopWatching=function(){r.getInstance().stopPolling(this.filterId),this.implementation.uninstallFilter(this.filterId,function(){}),this.callbacks=[]},l.prototype.get=function(t){var e=this;if(!i.isFunction(t)){var n=this.implementation.getLogs(this.filterId);return n.map(function(t){return e.formatter?e.formatter(t):t})}return this.implementation.getLogs(this.filterId,function(n,r){n?t(n):t(null,r.map(function(t){return e.formatter?e.formatter(t):t}))}),this},e.exports=l},{"../utils/utils":7,"./formatters":18,"./requestmanager":28}],18:[function(t,e,n){var r=t("../utils/utils"),o=t("../utils/config"),i=function(t){return r.toBigNumber(t)},a=function(t){return"latest"===t||"pending"===t||"earliest"===t},s=function(t){return void 0===t?o.defaultBlock:u(t)},u=function(t){return void 0===t?void 0:a(t)?t:r.toHex(t)},c=function(t){return t.from=t.from||o.defaultAccount,t.code&&(t.data=t.code,delete t.code),["gasPrice","gas","value","nonce"].filter(function(e){return void 0!==t[e]}).forEach(function(e){t[e]=r.fromDecimal(t[e])}),t},l=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),t.nonce=r.toDecimal(t.nonce),t.gas=r.toDecimal(t.gas),t.gasPrice=r.toBigNumber(t.gasPrice),t.value=r.toBigNumber(t.value),t},p=function(t){return t.gasLimit=r.toDecimal(t.gasLimit),t.gasUsed=r.toDecimal(t.gasUsed),t.size=r.toDecimal(t.size),t.timestamp=r.toDecimal(t.timestamp),null!==t.number&&(t.number=r.toDecimal(t.number)),t.difficulty=r.toBigNumber(t.difficulty),t.totalDifficulty=r.toBigNumber(t.totalDifficulty),r.isArray(t.transactions)&&t.transactions.forEach(function(t){return r.isString(t)?void 0:l(t)}),t},f=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),null!==t.logIndex&&(t.logIndex=r.toDecimal(t.logIndex)),t},m=function(t){return t.payload=r.toHex(t.payload),t.ttl=r.fromDecimal(t.ttl),t.workToProve=r.fromDecimal(t.workToProve),t.priority=r.fromDecimal(t.priority),r.isArray(t.topics)||(t.topics=t.topics?[t.topics]:[]),t.topics=t.topics.map(function(t){return r.fromAscii(t)}),t},h=function(t){return t.expiry=r.toDecimal(t.expiry),t.sent=r.toDecimal(t.sent),t.ttl=r.toDecimal(t.ttl),t.workProved=r.toDecimal(t.workProved),t.payloadRaw=t.payload,t.payload=r.toAscii(t.payload),r.isJson(t.payload)&&(t.payload=JSON.parse(t.payload)),t.topics||(t.topics=[]),t.topics=t.topics.map(function(t){return r.toAscii(t)}),t};e.exports={inputDefaultBlockNumberFormatter:s,inputBlockNumberFormatter:u,inputTransactionFormatter:c,inputPostFormatter:m,outputBigNumberFormatter:i,outputTransactionFormatter:l,outputBlockFormatter:p,outputLogFormatter:f,outputPostFormatter:h}},{"../utils/config":5,"../utils/utils":7}],19:[function(t,e,n){var r=t("../web3"),o=t("../solidity/coder"),i=t("../utils/utils"),a=t("./formatters"),s=t("../utils/sha3"),u=function(t,e){this._inputTypes=t.inputs.map(function(t){return t.type}),this._outputTypes=t.outputs.map(function(t){return t.type}),this._constant=t.constant,this._name=i.transformToFullName(t),this._address=e};u.prototype.extractCallback=function(t){return i.isFunction(t[t.length-1])?t.pop():void 0},u.prototype.extractDefaultBlock=function(t){return t.length>this._inputTypes.length&&!i.isObject(t[t.length-1])?a.inputDefaultBlockNumberFormatter(t.pop()):void 0},u.prototype.toPayload=function(t){var e={};return t.length>this._inputTypes.length&&i.isObject(t[t.length-1])&&(e=t[t.length-1]),e.to=this._address,e.data="0x"+this.signature()+o.encodeParams(this._inputTypes,t),e},u.prototype.signature=function(){return s(this._name).slice(0,8)},u.prototype.unpackOutput=function(t){if(t){t=t.length>=2?t.slice(2):t;var e=o.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},u.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.extractDefaultBlock(t),o=this.toPayload(t);if(!e){var i=r.eth.call(o,n);return this.unpackOutput(i)}var a=this;r.eth.call(o,n,function(t,n){e(t,a.unpackOutput(n))})},u.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):r.eth.sendTransaction(n)},u.prototype.estimateGas=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.estimateGas(n,e):r.eth.estimateGas(n)},u.prototype.displayName=function(){return i.extractDisplayName(this._name)},u.prototype.typeName=function(){return i.extractTypeName(this._name)},u.prototype.request=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t),r=this.unpackOutput.bind(this);return{method:this._constant?"eth_call":"eth_sendTransaction",callback:e,params:[n],format:r}},u.prototype.execute=function(){var t=!this._constant;return t?this.sendTransaction.apply(this,Array.prototype.slice.call(arguments)):this.call.apply(this,Array.prototype.slice.call(arguments))},u.prototype.attachToContract=function(t){var e=this.execute.bind(this);e.request=this.request.bind(this),e.call=this.call.bind(this),e.sendTransaction=this.sendTransaction.bind(this),e.estimateGas=this.estimateGas.bind(this);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=u},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":18}],20:[function(t,e,n){"use strict";var r="undefined"!=typeof window&&window.XMLHttpRequest?window.XMLHttpRequest:t("xmlhttprequest").XMLHttpRequest,o=t("./errors"),i=function(t){this.host=t||"http://localhost:8545"};i.prototype.send=function(t){var e=new r;e.open("POST",this.host,!1),e.setRequestHeader("Content-type","application/json");try{e.send(JSON.stringify(t))}catch(n){throw o.InvalidConnection(this.host)}var i=e.responseText;try{i=JSON.parse(i)}catch(a){throw o.InvalidResponse(i)}return i},i.prototype.sendAsync=function(t,e){var n=new r;n.onreadystatechange=function(){if(4===n.readyState){var t=n.responseText,r=null;try{t=JSON.parse(t)}catch(i){r=o.InvalidResponse(t)}e(r,t)}},n.open("POST",this.host,!0),n.setRequestHeader("Content-type","application/json");try{n.send(JSON.stringify(t))}catch(i){e(o.InvalidConnection(this.host))}},e.exports=i},{"./errors":14,xmlhttprequest:4}],21:[function(t,e,n){var r=t("../utils/utils"),o=function(t){this._iban=t};o.prototype.isValid=function(){return r.isIBAN(this._iban)},o.prototype.isDirect=function(){return 34===this._iban.length},o.prototype.isIndirect=function(){return 20===this._iban.length},o.prototype.checksum=function(){return this._iban.substr(2,2)},o.prototype.institution=function(){return this.isIndirect()?this._iban.substr(7,4):""},o.prototype.client=function(){return this.isIndirect()?this._iban.substr(11):""},o.prototype.address=function(){return this.isDirect()?this._iban.substr(4):""},e.exports=o},{"../utils/utils":7}],22:[function(t,e,n){var r=function(){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,void(this.messageId=1))};r.getInstance=function(){var t=new r;return t},r.prototype.toPayload=function(t,e){return t||console.error("jsonrpc method should be specified!"),{jsonrpc:"2.0",method:t,params:e||[],id:this.messageId++ -}},r.prototype.isValidResponse=function(t){return!!t&&!t.error&&"2.0"===t.jsonrpc&&"number"==typeof t.id&&void 0!==t.result},r.prototype.toBatchPayload=function(t){var e=this;return t.map(function(t){return e.toPayload(t.method,t.params)})},e.exports=r},{}],23:[function(t,e,n){var r=t("./requestmanager"),o=t("../utils/utils"),i=t("./errors"),a=function(t){this.name=t.name,this.call=t.call,this.params=t.params||0,this.inputFormatter=t.inputFormatter,this.outputFormatter=t.outputFormatter};a.prototype.getCall=function(t){return o.isFunction(this.call)?this.call(t):this.call},a.prototype.extractCallback=function(t){return o.isFunction(t[t.length-1])?t.pop():void 0},a.prototype.validateArgs=function(t){if(t.length!==this.params)throw i.InvalidNumberOfParams()},a.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter.map(function(e,n){return e?e(t[n]):t[n]}):t},a.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},a.prototype.attachToObject=function(t){var e=this.send.bind(this);e.request=this.request.bind(this),e.call=this.call;var n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},a.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},a.prototype.request=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));return t.format=this.formatOutput.bind(this),t},a.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return r.getInstance().sendAsync(t,function(n,r){t.callback(n,e.formatOutput(r))})}return this.formatOutput(r.getInstance().send(t))},e.exports=a},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],24:[function(t,e,n){var r=t("./contract"),o="0xc6d9d2cd449a754c494264e1809c50e34d64562b",i=[{constant:!0,inputs:[{name:"_owner",type:"address"}],name:"name",outputs:[{name:"o_name",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"owner",outputs:[{name:"",type:"address"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"content",outputs:[{name:"",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"addr",outputs:[{name:"",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"reserve",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"subRegistrar",outputs:[{name:"o_subRegistrar",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_newOwner",type:"address"}],name:"transfer",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_registrar",type:"address"}],name:"setSubRegistrar",outputs:[],type:"function"},{constant:!1,inputs:[],name:"Registrar",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_a",type:"address"},{name:"_primary",type:"bool"}],name:"setAddress",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_content",type:"bytes32"}],name:"setContent",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"disown",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"register",outputs:[{name:"",type:"address"}],type:"function"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"}],name:"Changed",type:"event"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"},{indexed:!0,name:"addr",type:"address"}],name:"PrimaryChanged",type:"event"}];e.exports=r(i).at(o)},{"./contract":12}],25:[function(t,e,n){var r=t("../utils/utils"),o=t("./property"),i=[],a=[new o({name:"listening",getter:"net_listening"}),new o({name:"peerCount",getter:"net_peerCount",outputFormatter:r.toDecimal})];e.exports={methods:i,properties:a}},{"../utils/utils":7,"./property":26}],26:[function(t,e,n){var r=t("./requestmanager"),o=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};o.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},o.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},o.prototype.attachToObject=function(t){var e={get:this.get.bind(this)},n=this.name.split("."),r=n[0];n.length>1&&(t[n[0]]=t[n[0]]||{},t=t[n[0]],r=n[1]),Object.defineProperty(t,r,e);var o=function(t,e){return t+e.charAt(0).toUpperCase()+e.slice(1)};t[o("get",r)]=this.getAsync.bind(this)},o.prototype.get=function(){return this.formatOutput(r.getInstance().send({method:this.getter}))},o.prototype.getAsync=function(t){var e=this;r.getInstance().sendAsync({method:this.getter},function(n,r){return n?t(n):void t(n,e.formatOutput(r))})},e.exports=o},{"./requestmanager":28}],27:[function(t,e,n){var r=function(){};r.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=r},{}],28:[function(t,e,n){var r=t("./jsonrpc"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./errors"),s=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls={},this.timeout=null,void(this.isPolling=!1))};s.getInstance=function(){var t=new s;return t},s.prototype.send=function(t){if(!this.provider)return console.error(a.InvalidProvider()),null;var e=r.getInstance().toPayload(t.method,t.params),n=this.provider.send(e);if(!r.getInstance().isValidResponse(n))throw a.InvalidResponse(n);return n.result},s.prototype.sendAsync=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(n,function(t,n){return t?e(t):r.getInstance().isValidResponse(n)?void e(null,n.result):e(a.InvalidResponse(n))})},s.prototype.sendBatch=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toBatchPayload(t);this.provider.sendAsync(n,function(t,n){return t?e(t):o.isArray(n)?void e(t,n):e(a.InvalidResponse(n))})},s.prototype.setProvider=function(t){this.provider=t,this.provider&&!this.isPolling&&(this.poll(),this.isPolling=!0)},s.prototype.startPolling=function(t,e,n,r){this.polls["poll_"+e]={data:t,id:e,callback:n,uninstall:r}},s.prototype.stopPolling=function(t){delete this.polls["poll_"+t]},s.prototype.reset=function(){for(var t in this.polls)this.polls[t].uninstall();this.polls={},this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},s.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),i.ETH_POLLING_TIMEOUT),0!==Object.keys(this.polls).length){if(!this.provider)return void console.error(a.InvalidProvider());var t=[],e=[];for(var n in this.polls)t.push(this.polls[n].data),e.push(n);if(0!==t.length){var s=r.getInstance().toBatchPayload(t),u=this;this.provider.sendAsync(s,function(t,n){if(!t){if(!o.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){var r=e[n];return u.polls[r]?(t.callback=u.polls[r].callback,t):!1}).filter(function(t){return!!t}).filter(function(t){var e=r.getInstance().isValidResponse(t);return e||t.callback(a.InvalidResponse(t)),e}).filter(function(t){return o.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}}},e.exports=s},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":22}],29:[function(t,e,n){var r=t("./method"),o=t("./formatters"),i=new r({name:"post",call:"shh_post",params:1,inputFormatter:[o.inputPostFormatter]}),a=new r({name:"newIdentity",call:"shh_newIdentity",params:0}),s=new r({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new r({name:"newGroup",call:"shh_newGroup",params:0}),c=new r({name:"addToGroup",call:"shh_addToGroup",params:0}),l=[i,a,s,u,c];e.exports={methods:l}},{"./formatters":18,"./method":23}],30:[function(t,e,n){var r=t("../web3"),o=t("./icap"),i=t("./namereg"),a=t("./contract"),s=function(t,e,n,r){var a=new o(e);if(!a.isValid())throw new Error("invalid iban address");if(a.isDirect())return u(t,a.address(),n,r);if(!r){var s=i.addr(a.institution());return c(t,s,n,a.client())}i.addr(a.insitution(),function(e,o){return c(t,o,n,a.client(),r)})},u=function(t,e,n,o){return r.eth.sendTransaction({address:e,from:t,value:n},o)},c=function(t,e,n,r,o){var i=[{constant:!1,inputs:[{name:"name",type:"bytes32"}],name:"deposit",outputs:[],type:"function"}];return a(i).at(e).deposit(r,{from:t,value:n},o)};e.exports=s},{"../web3":9,"./contract":12,"./icap":21,"./namereg":24}],31:[function(t,e,n){var r=t("./method"),o=function(){var t=function(t){var e=t[0];switch(e){case"latest":return t.shift(),this.params=0,"eth_newBlockFilter";case"pending":return t.shift(),this.params=0,"eth_newPendingTransactionFilter";default:return"eth_newFilter"}},e=new r({name:"newFilter",call:t,params:1}),n=new r({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),o=new r({name:"getLogs",call:"eth_getFilterLogs",params:1}),i=new r({name:"poll",call:"eth_getFilterChanges",params:1});return[e,n,o,i]},i=function(){var t=new r({name:"newFilter",call:"shh_newFilter",params:1}),e=new r({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),n=new r({name:"getLogs",call:"shh_getMessages",params:1}),o=new r({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,n,o]};e.exports={eth:o,shh:i}},{"./method":23}],32:[function(t,e,n){},{}],33:[function(t,e,n){!function(t,r){"object"==typeof n?e.exports=n=r():"function"==typeof define&&define.amd?define([],r):t.CryptoJS=r()}(this,function(){var t=t||function(t,e){var n={},r=n.lib={},o=r.Base=function(){function t(){}return{extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),i=r.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:4*t.length},toString:function(t){return(t||s).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes,o=t.sigBytes;if(this.clamp(),r%4)for(var i=0;o>i;i++){var a=n[i>>>2]>>>24-i%4*8&255;e[r+i>>>2]|=a<<24-(r+i)%4*8}else for(var i=0;o>i;i+=4)e[r+i>>>2]=n[i>>>2];return this.sigBytes+=o,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=o.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n,r=[],o=function(e){var e=e,n=987654321,r=4294967295;return function(){n=36969*(65535&n)+(n>>16)&r,e=18e3*(65535&e)+(e>>16)&r;var o=(n<<16)+e&r;return o/=4294967296,o+=.5,o*(t.random()>.5?1:-1)}},a=0;e>a;a+=4){var s=o(4294967296*(n||t.random()));n=987654071*s(),r.push(4294967296*s()|0)}return new i.init(r,e)}}),a=n.enc={},s=a.Hex={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push((i>>>4).toString(16)),r.push((15&i).toString(16))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r+=2)n[r>>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new i.init(n,e/2)}},u=a.Latin1={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push(String.fromCharCode(i))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r++)n[r>>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new i.init(n,e)}},c=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},l=r.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new i.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=c.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,o=n.sigBytes,a=this.blockSize,s=4*a,u=o/s;u=e?t.ceil(u):t.max((0|u)-this._minBufferSize,0);var c=u*a,l=t.min(4*c,o);if(c){for(var p=0;c>p;p+=a)this._doProcessBlock(r,p);var f=r.splice(0,c);n.sigBytes-=l}return new i.init(f,l)},clone:function(){var t=o.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),p=(r.Hasher=l.extend({cfg:o.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){l.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},blockSize:16,_createHelper:function(t){return function(e,n){return new t.init(n).finalize(e)}},_createHmacHelper:function(t){return function(e,n){return new p.HMAC.init(t,n).finalize(e)}}}),n.algo={});return n}(Math);return t})},{}],34:[function(t,e,n){!function(r,o,i){"object"==typeof n?e.exports=n=o(t("./core"),t("./x64-core")):"function"==typeof define&&define.amd?define(["./core","./x64-core"],o):o(r.CryptoJS)}(this,function(t){return function(e){var n=t,r=n.lib,o=r.WordArray,i=r.Hasher,a=n.x64,s=a.Word,u=n.algo,c=[],l=[],p=[];!function(){for(var t=1,e=0,n=0;24>n;n++){c[t+5*e]=(n+1)*(n+2)/2%64;var r=e%5,o=(2*t+3*e)%5;t=r,e=o}for(var t=0;5>t;t++)for(var e=0;5>e;e++)l[t+5*e]=e+(2*t+3*e)%5*5;for(var i=1,a=0;24>a;a++){for(var u=0,f=0,m=0;7>m;m++){if(1&i){var h=(1<h?f^=1<t;t++)f[t]=s.create()}();var m=u.SHA3=i.extend({cfg:i.cfg.extend({outputLength:512}),_doReset:function(){for(var t=this._state=[],e=0;25>e;e++)t[e]=new s.init;this.blockSize=(1600-2*this.cfg.outputLength)/32},_doProcessBlock:function(t,e){for(var n=this._state,r=this.blockSize/2,o=0;r>o;o++){var i=t[e+2*o],a=t[e+2*o+1];i=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8),a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8);var s=n[o];s.high^=a,s.low^=i}for(var u=0;24>u;u++){for(var m=0;5>m;m++){for(var h=0,d=0,y=0;5>y;y++){var s=n[m+5*y];h^=s.high,d^=s.low}var g=f[m];g.high=h,g.low=d}for(var m=0;5>m;m++)for(var v=f[(m+4)%5],b=f[(m+1)%5],w=b.high,_=b.low,h=v.high^(w<<1|_>>>31),d=v.low^(_<<1|w>>>31),y=0;5>y;y++){var s=n[m+5*y];s.high^=h,s.low^=d}for(var x=1;25>x;x++){var s=n[x],F=s.high,B=s.low,I=c[x];if(32>I)var h=F<>>32-I,d=B<>>32-I;else var h=B<>>64-I,d=F<>>64-I;var k=f[l[x]];k.high=h,k.low=d}var N=f[0],P=n[0];N.high=P.high,N.low=P.low;for(var m=0;5>m;m++)for(var y=0;5>y;y++){var x=m+5*y,s=n[x],O=f[x],T=f[(m+1)%5+5*y],A=f[(m+2)%5+5*y];s.high=O.high^~T.high&A.high,s.low=O.low^~T.low&A.low}var s=n[0],D=p[u];s.high^=D.high,s.low^=D.low}},_doFinalize:function(){var t=this._data,n=t.words,r=(8*this._nDataBytes,8*t.sigBytes),i=32*this.blockSize;n[r>>>5]|=1<<24-r%32,n[(e.ceil((r+1)/i)*i>>>5)-1]|=128,t.sigBytes=4*n.length,this._process();for(var a=this._state,s=this.cfg.outputLength/8,u=s/8,c=[],l=0;u>l;l++){var p=a[l],f=p.high,m=p.low;f=16711935&(f<<8|f>>>24)|4278255360&(f<<24|f>>>8),m=16711935&(m<<8|m>>>24)|4278255360&(m<<24|m>>>8),c.push(m),c.push(f)}return new o.init(c,s)},clone:function(){for(var t=i.clone.call(this),e=t._state=this._state.slice(0),n=0;25>n;n++)e[n]=e[n].clone();return t}});n.SHA3=i._createHelper(m),n.HmacSHA3=i._createHmacHelper(m)}(Math),t.SHA3})},{"./core":33,"./x64-core":35}],35:[function(t,e,n){!function(r,o){"object"==typeof n?e.exports=n=o(t("./core")):"function"==typeof define&&define.amd?define(["./core"],o):o(r.CryptoJS)}(this,function(t){return function(e){{var n=t,r=n.lib,o=r.Base,i=r.WordArray,a=n.x64={};a.Word=o.extend({init:function(t,e){this.high=t,this.low=e}}),a.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:8*t.length},toX32:function(){for(var t=this.words,e=t.length,n=[],r=0;e>r;r++){var o=t[r];n.push(o.high),n.push(o.low)}return i.create(n,this.sigBytes)},clone:function(){for(var t=o.clone.call(this),e=t.words=this.words.slice(0),n=e.length,r=0;n>r;r++)e[r]=e[r].clone();return t}})}}(),t})},{"./core":33}],"bignumber.js":[function(t,e,n){"use strict";e.exports=BigNumber},{}],web3:[function(t,e,n){var r=t("./lib/web3");r.providers.HttpProvider=t("./lib/web3/httpprovider"),r.providers.QtSyncProvider=t("./lib/web3/qtsync"),r.eth.contract=t("./lib/web3/contract"),r.eth.namereg=t("./lib/web3/namereg"),r.eth.sendIBANTransaction=t("./lib/web3/transfer"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/namereg":24,"./lib/web3/qtsync":27,"./lib/web3/transfer":30}]},{},["web3"]); \ No newline at end of file +require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ai;i+=64)n.push(this._outputFormatter(new a(t.dynamicPart().substr(i+64,64))));return n}return this._outputFormatter(t)},u.prototype.sliceParam=function(t,e,n){return"bytes"===this._mode?a.decodeBytes(t,e):s(n)?a.decodeArray(t,e):a.decodeParam(t,e)};var c=function(t){this._types=t};c.prototype._requireType=function(t){var e=this._types.filter(function(e){return e.isType(t)})[0];if(!e)throw Error("invalid solidity type!: "+t);return e},c.prototype._formatInput=function(t,e){return this._requireType(t).formatInput(e,s(t))},c.prototype.encodeParam=function(t,e){return this._formatInput(t,e).encode()},c.prototype.encodeParams=function(t,e){var n=this,r=t.map(function(t,r){return n._formatInput(t,e[r])});return a.encodeList(r)},c.prototype.decodeParam=function(t,e){return this.decodeParams([t],e)[0]},c.prototype.decodeParams=function(t,e){var n=this;return t.map(function(t,r){var o=n._requireType(t),i=o.sliceParam(e,r,t);return o.formatOutput(i,s(t))})};var l=new c([new u({name:"address",match:"strict",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputAddress}),new u({name:"bool",match:"strict",mode:"value",inputFormatter:i.formatInputBool,outputFormatter:i.formatOutputBool}),new u({name:"int",match:"prefix",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputInt}),new u({name:"uint",match:"prefix",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputUInt}),new u({name:"bytes",match:"strict",mode:"bytes",inputFormatter:i.formatInputDynamicBytes,outputFormatter:i.formatOutputDynamicBytes}),new u({name:"bytes",match:"prefix",mode:"value",inputFormatter:i.formatInputBytes,outputFormatter:i.formatOutputBytes}),new u({name:"string",match:"strict",mode:"bytes",inputFormatter:i.formatInputString,outputFormatter:i.formatOutputString}),new u({name:"real",match:"prefix",mode:"value",inputFormatter:i.formatInputReal,outputFormatter:i.formatOutputReal}),new u({name:"ureal",match:"prefix",mode:"value",inputFormatter:i.formatInputReal,outputFormatter:i.formatOutputUReal})]);e.exports=l},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(t,e,n){var r=t("bignumber.js"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./param"),s=function(t){var e=2*i.ETH_PADDING;r.config(i.ETH_BIGNUMBER_ROUNDING_MODE);var n=o.padLeft(o.toTwosComplement(t).round().toString(16),e);return new a(n)},u=function(t){var e=o.padRight(o.toHex(t).substr(2),64);return new a(e)},c=function(t){t=o.toHex(t).substr(2);var e=Math.floor((t.length+63)/64),n=o.padRight(t,64*e),r=Math.floor(t.length/2);return new a(s(r).value+n,32)},l=function(t){var e=o.fromAscii(t).substr(2),n=Math.floor((e.length+63)/64);return e=o.padRight(e,64*n),new a(s(t.length).value+e,32)},p=function(t){var e="000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0");return new a(e)},f=function(t){return s(new r(t).times(new r(2).pow(128)))},m=function(t){return"1"===new r(t.substr(0,1),16).toString(2).substr(0,1)},h=function(t){var e=t.staticPart()||"0";return m(e)?new r(e,16).minus(new r("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new r(e,16)},d=function(t){var e=t.staticPart()||"0";return new r(e,16)},y=function(t){return h(t).dividedBy(new r(2).pow(128))},g=function(t){return d(t).dividedBy(new r(2).pow(128))},v=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t.staticPart()?!0:!1},b=function(t){return"0x"+t.staticPart()},w=function(t){var e=2*new r(t.dynamicPart().slice(0,64),16).toNumber();return"0x"+t.dynamicPart().substr(64,e)},_=function(t){var e=2*new r(t.dynamicPart().slice(0,64),16).toNumber();return o.toAscii(t.dynamicPart().substr(64,e))},x=function(t){var e=t.staticPart();return"0x"+e.slice(e.length-40,e.length)};e.exports={formatInputInt:s,formatInputBytes:u,formatInputDynamicBytes:c,formatInputString:l,formatInputBool:p,formatInputReal:f,formatOutputInt:h,formatOutputUInt:d,formatOutputReal:y,formatOutputUReal:g,formatOutputBool:v,formatOutputBytes:b,formatOutputDynamicBytes:w,formatOutputString:_,formatOutputAddress:x}},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),o=function(t,e){this.value=t||"",this.offset=e};o.prototype.dynamicPartLength=function(){return this.dynamicPart().length/2},o.prototype.withOffset=function(t){return new o(this.value,t)},o.prototype.combine=function(t){return new o(this.value+t.value)},o.prototype.isDynamic=function(){return this.value.length>64||void 0!==this.offset},o.prototype.offsetAsBytes=function(){return this.isDynamic()?r.padLeft(r.toTwosComplement(this.offset).toString(16),64):""},o.prototype.staticPart=function(){return this.isDynamic()?this.offsetAsBytes():this.value},o.prototype.dynamicPart=function(){return this.isDynamic()?this.value:""},o.prototype.encode=function(){return this.staticPart()+this.dynamicPart()},o.encodeList=function(t){var e=32*t.length,n=t.map(function(t){if(!t.isDynamic())return t;var n=e;return e+=t.dynamicPartLength(),t.withOffset(n)});return n.reduce(function(t,e){return t+e.dynamicPart()},n.reduce(function(t,e){return t+e.staticPart()},""))},o.decodeParam=function(t,e){return e=e||0,new o(t.substr(64*e,64))};var i=function(t,e){return parseInt("0x"+t.substr(64*e,64))};o.decodeBytes=function(t,e){e=e||0;var n=i(t,e),r=parseInt("0x"+t.substr(2*n,64));return r=Math.floor((r+31)/32),new o(t.substr(2*n,64*(1+r)),0)},o.decodeArray=function(t,e){e=e||0;var n=i(t,e),r=parseInt("0x"+t.substr(2*n,64));return new o(t.substr(2*n,64*(r+1)),0)},e.exports=o},{"../utils/utils":7}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e,n){var r=t("bignumber.js"),o=["wei","kwei","Mwei","Gwei","szabo","finney","femtoether","picoether","nanoether","microether","milliether","nano","micro","milli","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:o,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:r.ROUND_DOWN},ETH_POLLING_TIMEOUT:500,defaultBlock:"latest",defaultAccount:void 0}},{"bignumber.js":"bignumber.js"}],6:[function(t,e,n){var r=t("./utils"),o=t("crypto-js/sha3");e.exports=function(t,e){return"0x"!==t.substr(0,2)||e||(console.warn("requirement of using web3.fromAscii before sha3 is deprecated"),console.warn("new usage: 'web3.sha3(\"hello\")'"),console.warn("see https://github.com/ethereum/web3.js/pull/205"),console.warn("if you need to hash hex value, you can do 'sha3(\"0xfff\", true)'"),t=r.toAscii(t)),o(t,{outputLength:256}).toString()}},{"./utils":7,"crypto-js/sha3":34}],7:[function(t,e,n){var r=t("bignumber.js"),o={wei:"1",kwei:"1000",ada:"1000",femtoether:"1000",mwei:"1000000",babbage:"1000000",picoether:"1000000",gwei:"1000000000",shannon:"1000000000",nanoether:"1000000000",nano:"1000000000",szabo:"1000000000000",microether:"1000000000000",micro:"1000000000000",finney:"1000000000000000",milliether:"1000000000000000",milli:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},i=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t,e,n){return t+new Array(e-t.length+1).join(n?n:"0")},s=function(t){var e="",n=0,r=t.length;for("0x"===t.substring(0,2)&&(n=2);r>n;n+=2){var o=parseInt(t.substr(n,2),16);e+=String.fromCharCode(o)}return e},u=function(t){for(var e="",n=0;n50){if(a.stopWatching(),i=!0,!n)throw new Error("Contract transaction couldn't be found after 50 blocks");n(new Error("Contract transaction couldn't be found after 50 blocks"))}else r.eth.getTransactionReceipt(t.transactionHash,function(o,s){s&&!i&&r.eth.getCode(s.contractAddress,function(r,o){if(!i)if(a.stopWatching(),i=!0,o.length>2)t.address=s.contractAddress,l(t,e),p(t,e),n&&n(null,t);else{if(!n)throw new Error("The contract code couldn't be stored, please check your gas amount.");n(new Error("The contract code couldn't be stored, please check your gas amount."))}})})})},h=function(t){this.abi=t};h.prototype["new"]=function(){var t,e=this,n=new d(this.abi),i={},a=Array.prototype.slice.call(arguments);o.isFunction(a[a.length-1])&&(t=a.pop());var s=a[a.length-1];o.isObject(s)&&!o.isArray(s)&&(i=a.pop());var u=c(this.abi,a);if(i.data+=u,t)r.eth.sendTransaction(i,function(r,o){r?t(r):(n.transactionHash=o,t(null,n),m(n,e.abi,t))});else{var l=r.eth.sendTransaction(i);n.transactionHash=l,m(n,e.abi)}return n},h.prototype.at=function(t,e){var n=new d(this.abi,t);return l(n,this.abi),p(n,this.abi),e&&e(null,n),n};var d=function(t,e){this.address=e};e.exports=f},{"../solidity/coder":1,"../utils/utils":7,"../web3":9,"./allevents":10,"./event":16,"./function":19}],13:[function(t,e,n){var r=t("./method"),o=new r({name:"putString",call:"db_putString",params:3}),i=new r({name:"getString",call:"db_getString",params:2}),a=new r({name:"putHex",call:"db_putHex",params:3}),s=new r({name:"getHex",call:"db_getHex",params:2}),u=[o,i,a,s];e.exports={methods:u}},{"./method":24}],14:[function(t,e,n){e.exports={InvalidNumberOfParams:function(){return new Error("Invalid number of input parameters")},InvalidConnection:function(t){return new Error("CONNECTION ERROR: Couldn't connect to node "+t+", is it running?")},InvalidProvider:function(){return new Error("Providor not set or invalid")},InvalidResponse:function(t){var e=t&&t.error&&t.error.message?t.error.message:"Invalid JSON RPC response: "+t;return new Error(e)}}},{}],15:[function(t,e,n){"use strict";var r=t("./formatters"),o=t("../utils/utils"),i=t("./method"),a=t("./property"),s=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getBlockByHash":"eth_getBlockByNumber"},u=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getTransactionByBlockHashAndIndex":"eth_getTransactionByBlockNumberAndIndex"},c=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getUncleByBlockHashAndIndex":"eth_getUncleByBlockNumberAndIndex"},l=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getBlockTransactionCountByHash":"eth_getBlockTransactionCountByNumber"},p=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getUncleCountByBlockHash":"eth_getUncleCountByBlockNumber"},f=new i({name:"getBalance",call:"eth_getBalance",params:2,inputFormatter:[o.toAddress,r.inputDefaultBlockNumberFormatter],outputFormatter:r.outputBigNumberFormatter}),m=new i({name:"getStorageAt",call:"eth_getStorageAt",params:3,inputFormatter:[null,o.toHex,r.inputDefaultBlockNumberFormatter]}),h=new i({name:"getCode",call:"eth_getCode",params:2,inputFormatter:[o.toAddress,r.inputDefaultBlockNumberFormatter]}),d=new i({name:"getBlock",call:s,params:2,inputFormatter:[r.inputBlockNumberFormatter,function(t){return!!t}],outputFormatter:r.outputBlockFormatter}),y=new i({name:"getUncle",call:c,params:2,inputFormatter:[r.inputBlockNumberFormatter,o.toHex],outputFormatter:r.outputBlockFormatter}),g=new i({name:"getCompilers",call:"eth_getCompilers",params:0}),v=new i({name:"getBlockTransactionCount",call:l,params:1,inputFormatter:[r.inputBlockNumberFormatter],outputFormatter:o.toDecimal}),b=new i({name:"getBlockUncleCount",call:p,params:1,inputFormatter:[r.inputBlockNumberFormatter],outputFormatter:o.toDecimal}),w=new i({name:"getTransaction",call:"eth_getTransactionByHash",params:1,outputFormatter:r.outputTransactionFormatter}),_=new i({name:"getTransactionFromBlock",call:u,params:2,inputFormatter:[r.inputBlockNumberFormatter,o.toHex],outputFormatter:r.outputTransactionFormatter}),x=new i({name:"getTransactionReceipt",call:"eth_getTransactionReceipt",params:1,outputFormatter:r.outputTransactionReceiptFormatter}),I=new i({name:"getTransactionCount",call:"eth_getTransactionCount",params:2,inputFormatter:[null,r.inputDefaultBlockNumberFormatter],outputFormatter:o.toDecimal}),F=new i({name:"sendRawTransaction",call:"eth_sendRawTransaction",params:1,inputFormatter:[null]}),k=new i({name:"sendTransaction",call:"eth_sendTransaction",params:1,inputFormatter:[r.inputTransactionFormatter]}),B=new i({name:"call",call:"eth_call",params:2,inputFormatter:[r.inputTransactionFormatter,r.inputDefaultBlockNumberFormatter]}),T=new i({name:"estimateGas",call:"eth_estimateGas",params:1,inputFormatter:[r.inputTransactionFormatter],outputFormatter:o.toDecimal}),N=new i({name:"compile.solidity",call:"eth_compileSolidity",params:1}),P=new i({name:"compile.lll",call:"eth_compileLLL",params:1}),O=new i({name:"compile.serpent",call:"eth_compileSerpent",params:1}),A=new i({name:"submitWork",call:"eth_submitWork",params:3}),C=new i({name:"getWork",call:"eth_getWork",params:0}),D=[f,m,h,d,y,g,v,b,w,_,x,I,B,T,F,k,N,P,O,A,C],S=[new a({name:"coinbase",getter:"eth_coinbase"}),new a({name:"mining",getter:"eth_mining"}),new a({name:"hashrate",getter:"eth_hashrate",outputFormatter:o.toDecimal}),new a({name:"gasPrice",getter:"eth_gasPrice",outputFormatter:r.outputBigNumberFormatter}),new a({name:"accounts",getter:"eth_accounts"}),new a({name:"blockNumber",getter:"eth_blockNumber",outputFormatter:o.toDecimal})];e.exports={methods:D,properties:S}},{"../utils/utils":7,"./formatters":18,"./method":24,"./property":27}],16:[function(t,e,n){var r=t("../utils/utils"),o=t("../solidity/coder"),i=t("./formatters"),a=t("../utils/sha3"),s=t("./filter"),u=t("./watches"),c=function(t,e){this._params=t.inputs,this._name=r.transformToFullName(t),this._address=e,this._anonymous=t.anonymous};c.prototype.types=function(t){return this._params.filter(function(e){return e.indexed===t}).map(function(t){return t.type})},c.prototype.displayName=function(){return r.extractDisplayName(this._name)},c.prototype.typeName=function(){return r.extractTypeName(this._name)},c.prototype.signature=function(){return a(this._name)},c.prototype.encode=function(t,e){t=t||{},e=e||{};var n={};["fromBlock","toBlock"].filter(function(t){return void 0!==e[t]}).forEach(function(t){n[t]=i.inputBlockNumberFormatter(e[t])}),n.topics=[],n.address=this._address,this._anonymous||n.topics.push("0x"+this.signature());var a=this._params.filter(function(t){return t.indexed===!0}).map(function(e){var n=t[e.name];return void 0===n||null===n?null:r.isArray(n)?n.map(function(t){return"0x"+o.encodeParam(e.type,t)}):"0x"+o.encodeParam(e.type,n)});return n.topics=n.topics.concat(a),n},c.prototype.decode=function(t){t.data=t.data||"",t.topics=t.topics||[];var e=this._anonymous?t.topics:t.topics.slice(1),n=e.map(function(t){return t.slice(2)}).join(""),r=o.decodeParams(this.types(!0),n),a=t.data.slice(2),s=o.decodeParams(this.types(!1),a),u=i.outputLogFormatter(t);return u.event=this.displayName(),u.address=t.address,u.args=this._params.reduce(function(t,e){return t[e.name]=e.indexed?r.shift():s.shift(),t},{}),delete u.data,delete u.topics,u},c.prototype.execute=function(t,e,n){r.isFunction(arguments[arguments.length-1])&&(n=arguments[arguments.length-1],2===arguments.length&&(e=null),1===arguments.length&&(e=null,t={}));var o=this.encode(t,e),i=this.decode.bind(this);return new s(o,u.eth(),i,n)},c.prototype.attachToContract=function(t){var e=this.execute.bind(this),n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=this.execute.bind(this,t)},e.exports=c},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"./filter":17,"./formatters":18,"./watches":31}],17:[function(t,e,n){var r=t("./requestmanager"),o=t("./formatters"),i=t("../utils/utils"),a=function(t){return null===t||"undefined"==typeof t?null:(t=String(t),0===t.indexOf("0x")?t:i.fromAscii(t))},s=function(t){return i.isString(t)?t:(t=t||{},t.topics=t.topics||[],t.topics=t.topics.map(function(t){return i.isArray(t)?t.map(a):a(t)}),{topics:t.topics,to:t.to,address:t.address,fromBlock:o.inputBlockNumberFormatter(t.fromBlock),toBlock:o.inputBlockNumberFormatter(t.toBlock)})},u=function(t,e){i.isString(t.options)||t.get(function(t,n){t&&e(t),i.isArray(n)&&n.forEach(function(t){e(null,t)})})},c=function(t){var e=function(e,n){return e?t.callbacks.forEach(function(t){t(e)}):void n.forEach(function(e){e=t.formatter?t.formatter(e):e,t.callbacks.forEach(function(t){t(null,e)})})};r.getInstance().startPolling({method:t.implementation.poll.call,params:[t.filterId]},t.filterId,e,t.stopWatching.bind(t))},l=function(t,e,n,r){var o=this,i={};e.forEach(function(t){t.attachToObject(i)}),this.options=s(t),this.implementation=i,this.filterId=null,this.callbacks=[],this.pollFilters=[],this.formatter=n,this.implementation.newFilter(this.options,function(t,e){if(t)o.callbacks.forEach(function(e){e(t)});else if(o.filterId=e,o.callbacks.forEach(function(t){u(o,t)}),o.callbacks.length>0&&c(o),r)return o.watch(r)})};l.prototype.watch=function(t){return this.callbacks.push(t),this.filterId&&(u(this,t),c(this)),this},l.prototype.stopWatching=function(){r.getInstance().stopPolling(this.filterId),this.implementation.uninstallFilter(this.filterId,function(){}),this.callbacks=[]},l.prototype.get=function(t){var e=this;if(!i.isFunction(t)){var n=this.implementation.getLogs(this.filterId);return n.map(function(t){return e.formatter?e.formatter(t):t})}return this.implementation.getLogs(this.filterId,function(n,r){n?t(n):t(null,r.map(function(t){return e.formatter?e.formatter(t):t}))}),this},e.exports=l},{"../utils/utils":7,"./formatters":18,"./requestmanager":28}],18:[function(t,e,n){var r=t("../utils/utils"),o=t("../utils/config"),i=function(t){return r.toBigNumber(t)},a=function(t){return"latest"===t||"pending"===t||"earliest"===t},s=function(t){return void 0===t?o.defaultBlock:u(t)},u=function(t){return void 0===t?void 0:a(t)?t:r.toHex(t)},c=function(t){return t.from=t.from||o.defaultAccount,t.code&&(t.data=t.code,delete t.code),["gasPrice","gas","value","nonce"].filter(function(e){return void 0!==t[e]}).forEach(function(e){t[e]=r.fromDecimal(t[e])}),t},l=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),t.nonce=r.toDecimal(t.nonce),t.gas=r.toDecimal(t.gas),t.gasPrice=r.toBigNumber(t.gasPrice),t.value=r.toBigNumber(t.value),t},p=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),t.cumulativeGasUsed=r.toDecimal(t.cumulativeGasUsed),t.gasUsed=r.toDecimal(t.gasUsed),r.isArray(t.logs)&&(t.logs=t.logs.map(function(t){return m(t)})),t},f=function(t){return t.gasLimit=r.toDecimal(t.gasLimit),t.gasUsed=r.toDecimal(t.gasUsed),t.size=r.toDecimal(t.size),t.timestamp=r.toDecimal(t.timestamp),null!==t.number&&(t.number=r.toDecimal(t.number)),t.difficulty=r.toBigNumber(t.difficulty),t.totalDifficulty=r.toBigNumber(t.totalDifficulty),r.isArray(t.transactions)&&t.transactions.forEach(function(t){return r.isString(t)?void 0:l(t)}),t},m=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),null!==t.logIndex&&(t.logIndex=r.toDecimal(t.logIndex)),t},h=function(t){return t.payload=r.toHex(t.payload),t.ttl=r.fromDecimal(t.ttl),t.workToProve=r.fromDecimal(t.workToProve),t.priority=r.fromDecimal(t.priority),r.isArray(t.topics)||(t.topics=t.topics?[t.topics]:[]),t.topics=t.topics.map(function(t){return r.fromAscii(t)}),t},d=function(t){return t.expiry=r.toDecimal(t.expiry),t.sent=r.toDecimal(t.sent),t.ttl=r.toDecimal(t.ttl),t.workProved=r.toDecimal(t.workProved),t.payloadRaw=t.payload,t.payload=r.toAscii(t.payload),r.isJson(t.payload)&&(t.payload=JSON.parse(t.payload)),t.topics||(t.topics=[]),t.topics=t.topics.map(function(t){return r.toAscii(t)}),t};e.exports={inputDefaultBlockNumberFormatter:s,inputBlockNumberFormatter:u,inputTransactionFormatter:c,inputPostFormatter:h,outputBigNumberFormatter:i,outputTransactionFormatter:l,outputTransactionReceiptFormatter:p,outputBlockFormatter:f,outputLogFormatter:m,outputPostFormatter:d}},{"../utils/config":5,"../utils/utils":7}],19:[function(t,e,n){var r=t("../web3"),o=t("../solidity/coder"),i=t("../utils/utils"),a=t("./formatters"),s=t("../utils/sha3"),u=function(t,e){this._inputTypes=t.inputs.map(function(t){return t.type}),this._outputTypes=t.outputs.map(function(t){return t.type}),this._constant=t.constant,this._name=i.transformToFullName(t),this._address=e};u.prototype.extractCallback=function(t){return i.isFunction(t[t.length-1])?t.pop():void 0},u.prototype.extractDefaultBlock=function(t){return t.length>this._inputTypes.length&&!i.isObject(t[t.length-1])?a.inputDefaultBlockNumberFormatter(t.pop()):void 0},u.prototype.toPayload=function(t){var e={};return t.length>this._inputTypes.length&&i.isObject(t[t.length-1])&&(e=t[t.length-1]),e.to=this._address,e.data="0x"+this.signature()+o.encodeParams(this._inputTypes,t),e},u.prototype.signature=function(){return s(this._name).slice(0,8)},u.prototype.unpackOutput=function(t){if(t){t=t.length>=2?t.slice(2):t;var e=o.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},u.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.extractDefaultBlock(t),o=this.toPayload(t);if(!e){var i=r.eth.call(o,n);return this.unpackOutput(i)}var a=this;r.eth.call(o,n,function(t,n){e(t,a.unpackOutput(n))})},u.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):r.eth.sendTransaction(n)},u.prototype.estimateGas=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.estimateGas(n,e):r.eth.estimateGas(n)},u.prototype.displayName=function(){return i.extractDisplayName(this._name)},u.prototype.typeName=function(){return i.extractTypeName(this._name)},u.prototype.request=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t),r=this.unpackOutput.bind(this);return{method:this._constant?"eth_call":"eth_sendTransaction",callback:e,params:[n],format:r}},u.prototype.execute=function(){var t=!this._constant;return t?this.sendTransaction.apply(this,Array.prototype.slice.call(arguments)):this.call.apply(this,Array.prototype.slice.call(arguments))},u.prototype.attachToContract=function(t){var e=this.execute.bind(this);e.request=this.request.bind(this),e.call=this.call.bind(this),e.sendTransaction=this.sendTransaction.bind(this),e.estimateGas=this.estimateGas.bind(this);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=u},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":18}],20:[function(t,e,n){"use strict";var r="undefined"!=typeof window&&window.XMLHttpRequest?window.XMLHttpRequest:t("xmlhttprequest").XMLHttpRequest,o=t("./errors"),i=function(t){this.host=t||"http://localhost:8545"};i.prototype.isConnected=function(){var t=new r;t.open("POST",this.host,!1),t.setRequestHeader("Content-type","application/json");try{return t.send(JSON.stringify({id:9999999999,jsonrpc:"2.0",method:"net_listening",params:[]})),!0}catch(e){return!1; + +}},i.prototype.send=function(t){var e=new r;e.open("POST",this.host,!1),e.setRequestHeader("Content-type","application/json");try{e.send(JSON.stringify(t))}catch(n){throw o.InvalidConnection(this.host)}var i=e.responseText;try{i=JSON.parse(i)}catch(a){throw o.InvalidResponse(e.responseText)}return i},i.prototype.sendAsync=function(t,e){var n=new r;n.onreadystatechange=function(){if(4===n.readyState){var t=n.responseText,r=null;try{t=JSON.parse(t)}catch(i){r=o.InvalidResponse(n.responseText)}e(r,t)}},n.open("POST",this.host,!0),n.setRequestHeader("Content-type","application/json");try{n.send(JSON.stringify(t))}catch(i){e(o.InvalidConnection(this.host))}},e.exports=i},{"./errors":14,xmlhttprequest:4}],21:[function(t,e,n){var r=t("../utils/utils"),o=function(t){this._iban=t};o.prototype.isValid=function(){return r.isIBAN(this._iban)},o.prototype.isDirect=function(){return 34===this._iban.length},o.prototype.isIndirect=function(){return 20===this._iban.length},o.prototype.checksum=function(){return this._iban.substr(2,2)},o.prototype.institution=function(){return this.isIndirect()?this._iban.substr(7,4):""},o.prototype.client=function(){return this.isIndirect()?this._iban.substr(11):""},o.prototype.address=function(){return this.isDirect()?this._iban.substr(4):""},e.exports=o},{"../utils/utils":7}],22:[function(t,e,n){"use strict";var r=t("../utils/utils"),o=t("./errors"),i='{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}',a=function(e,n){var o=this;this.responseCallbacks={},this.path=e,n=n||t("net"),this.connection=n.connect({path:this.path}),this.connection.on("error",function(t){console.error("IPC Connection Error",t),o._timeout()}),this.connection.on("end",function(){o._timeout()}),this.connection.on("data",function(t){o._parseResponse(t.toString()).forEach(function(t){var e=null;r.isArray(t)?t.forEach(function(t){o.responseCallbacks[t.id]&&(e=t.id)}):e=t.id,o.responseCallbacks[e]&&(o.responseCallbacks[e](null,t),delete o.responseCallbacks[e])})})};a.prototype._parseResponse=function(t){var e=this,n=[],r=t.replace(/\}\{/g,"}|--|{").replace(/\}\]\[\{/g,"}]|--|[{").replace(/\}\[\{/g,"}|--|[{").replace(/\}\]\{/g,"}]|--|{").split("|--|");return r.forEach(function(t){e.lastChunk&&(t=e.lastChunk+t);var r=null;try{r=JSON.parse(t)}catch(i){return e.lastChunk=t,clearTimeout(e.lastChunkTimeout),void(e.lastChunkTimeout=setTimeout(function(){throw e.timeout(),o.InvalidResponse(t)},15e3))}clearTimeout(e.lastChunkTimeout),e.lastChunk=null,r&&n.push(r)}),n},a.prototype._addResponseCallback=function(t,e){var n=t.id||t[0].id,r=t.method||t[0].method;this.responseCallbacks[n]=e,this.responseCallbacks[n].method=r},a.prototype._timeout=function(){for(var t in this.responseCallbacks)this.responseCallbacks.hasOwnProperty(t)&&(this.responseCallbacks[t](i.replace("__id__",t).replace("__method__",this.responseCallbacks[t].method)),delete this.responseCallbacks[t])},a.prototype.isConnected=function(){var t=this;return t.connection.writable||t.connection.connect({path:t.path}),!!this.connection.writable},a.prototype.send=function(t){if(this.connection.writeSync){var e;this.connection.writable||this.connection.connect({path:this.path});var n=this.connection.writeSync(JSON.stringify(t));try{e=JSON.parse(n)}catch(r){throw o.InvalidResponse(n)}return e}throw new Error('You tried to send "'+t.method+'" synchronously. Synchronous requests are not supported by the IPC provider.')},a.prototype.sendAsync=function(t,e){this.connection.writable||this.connection.connect({path:this.path}),this.connection.write(JSON.stringify(t)),this._addResponseCallback(t,e)},e.exports=a},{"../utils/utils":7,"./errors":14,net:32}],23:[function(t,e,n){var r=function(){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,void(this.messageId=1))};r.getInstance=function(){var t=new r;return t},r.prototype.toPayload=function(t,e){return t||console.error("jsonrpc method should be specified!"),{jsonrpc:"2.0",method:t,params:e||[],id:this.messageId++}},r.prototype.isValidResponse=function(t){return!!t&&!t.error&&"2.0"===t.jsonrpc&&"number"==typeof t.id&&void 0!==t.result},r.prototype.toBatchPayload=function(t){var e=this;return t.map(function(t){return e.toPayload(t.method,t.params)})},e.exports=r},{}],24:[function(t,e,n){var r=t("./requestmanager"),o=t("../utils/utils"),i=t("./errors"),a=function(t){this.name=t.name,this.call=t.call,this.params=t.params||0,this.inputFormatter=t.inputFormatter,this.outputFormatter=t.outputFormatter};a.prototype.getCall=function(t){return o.isFunction(this.call)?this.call(t):this.call},a.prototype.extractCallback=function(t){return o.isFunction(t[t.length-1])?t.pop():void 0},a.prototype.validateArgs=function(t){if(t.length!==this.params)throw i.InvalidNumberOfParams()},a.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter.map(function(e,n){return e?e(t[n]):t[n]}):t},a.prototype.formatOutput=function(t){return this.outputFormatter&&t?this.outputFormatter(t):t},a.prototype.attachToObject=function(t){var e=this.send.bind(this);e.request=this.request.bind(this),e.call=this.call;var n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},a.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},a.prototype.request=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));return t.format=this.formatOutput.bind(this),t},a.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return r.getInstance().sendAsync(t,function(n,r){t.callback(n,e.formatOutput(r))})}return this.formatOutput(r.getInstance().send(t))},e.exports=a},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],25:[function(t,e,n){var r=t("./contract"),o="0xc6d9d2cd449a754c494264e1809c50e34d64562b",i=[{constant:!0,inputs:[{name:"_owner",type:"address"}],name:"name",outputs:[{name:"o_name",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"owner",outputs:[{name:"",type:"address"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"content",outputs:[{name:"",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"addr",outputs:[{name:"",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"reserve",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"subRegistrar",outputs:[{name:"o_subRegistrar",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_newOwner",type:"address"}],name:"transfer",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_registrar",type:"address"}],name:"setSubRegistrar",outputs:[],type:"function"},{constant:!1,inputs:[],name:"Registrar",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_a",type:"address"},{name:"_primary",type:"bool"}],name:"setAddress",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_content",type:"bytes32"}],name:"setContent",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"disown",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"register",outputs:[{name:"",type:"address"}],type:"function"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"}],name:"Changed",type:"event"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"},{indexed:!0,name:"addr",type:"address"}],name:"PrimaryChanged",type:"event"}];e.exports=r(i).at(o)},{"./contract":12}],26:[function(t,e,n){var r=t("../utils/utils"),o=t("./property"),i=[],a=[new o({name:"listening",getter:"net_listening"}),new o({name:"peerCount",getter:"net_peerCount",outputFormatter:r.toDecimal})];e.exports={methods:i,properties:a}},{"../utils/utils":7,"./property":27}],27:[function(t,e,n){var r=t("./requestmanager"),o=t("../utils/utils"),i=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};i.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},i.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},i.prototype.extractCallback=function(t){return o.isFunction(t[t.length-1])?t.pop():void 0},i.prototype.attachToObject=function(t){var e={get:this.get.bind(this)},n=this.name.split("."),r=n[0];n.length>1&&(t[n[0]]=t[n[0]]||{},t=t[n[0]],r=n[1]),Object.defineProperty(t,r,e);var o=function(t,e){return t+e.charAt(0).toUpperCase()+e.slice(1)},i=this.getAsync.bind(this);i.request=this.request.bind(this),t[o("get",r)]=i},i.prototype.get=function(){return this.formatOutput(r.getInstance().send({method:this.getter}))},i.prototype.getAsync=function(t){var e=this;r.getInstance().sendAsync({method:this.getter},function(n,r){return n?t(n):void t(n,e.formatOutput(r))})},i.prototype.request=function(){var t={method:this.getter,params:[],callback:this.extractCallback(Array.prototype.slice.call(arguments))};return t.format=this.formatOutput.bind(this),t},e.exports=i},{"../utils/utils":7,"./requestmanager":28}],28:[function(t,e,n){var r=t("./jsonrpc"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./errors"),s=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls={},this.timeout=null,void(this.isPolling=!1))};s.getInstance=function(){var t=new s;return t},s.prototype.send=function(t){if(!this.provider)return console.error(a.InvalidProvider()),null;var e=r.getInstance().toPayload(t.method,t.params),n=this.provider.send(e);if(!r.getInstance().isValidResponse(n))throw a.InvalidResponse(n);return n.result},s.prototype.sendAsync=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(n,function(t,n){return t?e(t):r.getInstance().isValidResponse(n)?void e(null,n.result):e(a.InvalidResponse(n))})},s.prototype.sendBatch=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toBatchPayload(t);this.provider.sendAsync(n,function(t,n){return t?e(t):o.isArray(n)?void e(t,n):e(a.InvalidResponse(n))})},s.prototype.setProvider=function(t){this.provider=t,this.provider&&!this.isPolling&&(this.poll(),this.isPolling=!0)},s.prototype.startPolling=function(t,e,n,r){this.polls["poll_"+e]={data:t,id:e,callback:n,uninstall:r}},s.prototype.stopPolling=function(t){delete this.polls["poll_"+t]},s.prototype.reset=function(){for(var t in this.polls)this.polls[t].uninstall();this.polls={},this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},s.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),i.ETH_POLLING_TIMEOUT),0!==Object.keys(this.polls).length){if(!this.provider)return void console.error(a.InvalidProvider());var t=[],e=[];for(var n in this.polls)t.push(this.polls[n].data),e.push(n);if(0!==t.length){var s=r.getInstance().toBatchPayload(t),u=this;this.provider.sendAsync(s,function(t,n){if(!t){if(!o.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){var r=e[n];return u.polls[r]?(t.callback=u.polls[r].callback,t):!1}).filter(function(t){return!!t}).filter(function(t){var e=r.getInstance().isValidResponse(t);return e||t.callback(a.InvalidResponse(t)),e}).filter(function(t){return o.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}}},e.exports=s},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":23}],29:[function(t,e,n){var r=t("./method"),o=t("./formatters"),i=new r({name:"post",call:"shh_post",params:1,inputFormatter:[o.inputPostFormatter]}),a=new r({name:"newIdentity",call:"shh_newIdentity",params:0}),s=new r({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new r({name:"newGroup",call:"shh_newGroup",params:0}),c=new r({name:"addToGroup",call:"shh_addToGroup",params:0}),l=[i,a,s,u,c];e.exports={methods:l}},{"./formatters":18,"./method":24}],30:[function(t,e,n){var r=t("../web3"),o=t("./icap"),i=t("./namereg"),a=t("./contract"),s=function(t,e,n,r){var a=new o(e);if(!a.isValid())throw new Error("invalid iban address");if(a.isDirect())return u(t,a.address(),n,r);if(!r){var s=i.addr(a.institution());return c(t,s,n,a.client())}i.addr(a.insitution(),function(e,o){return c(t,o,n,a.client(),r)})},u=function(t,e,n,o){return r.eth.sendTransaction({address:e,from:t,value:n},o)},c=function(t,e,n,r,o){var i=[{constant:!1,inputs:[{name:"name",type:"bytes32"}],name:"deposit",outputs:[],type:"function"}];return a(i).at(e).deposit(r,{from:t,value:n},o)};e.exports=s},{"../web3":9,"./contract":12,"./icap":21,"./namereg":25}],31:[function(t,e,n){var r=t("./method"),o=function(){var t=function(t){var e=t[0];switch(e){case"latest":return t.shift(),this.params=0,"eth_newBlockFilter";case"pending":return t.shift(),this.params=0,"eth_newPendingTransactionFilter";default:return"eth_newFilter"}},e=new r({name:"newFilter",call:t,params:1}),n=new r({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),o=new r({name:"getLogs",call:"eth_getFilterLogs",params:1}),i=new r({name:"poll",call:"eth_getFilterChanges",params:1});return[e,n,o,i]},i=function(){var t=new r({name:"newFilter",call:"shh_newFilter",params:1}),e=new r({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),n=new r({name:"getLogs",call:"shh_getMessages",params:1}),o=new r({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,n,o]};e.exports={eth:o,shh:i}},{"./method":24}],32:[function(t,e,n){},{}],33:[function(t,e,n){!function(t,r){"object"==typeof n?e.exports=n=r():"function"==typeof define&&define.amd?define([],r):t.CryptoJS=r()}(this,function(){var t=t||function(t,e){var n={},r=n.lib={},o=r.Base=function(){function t(){}return{extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),i=r.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:4*t.length},toString:function(t){return(t||s).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes,o=t.sigBytes;if(this.clamp(),r%4)for(var i=0;o>i;i++){var a=n[i>>>2]>>>24-i%4*8&255;e[r+i>>>2]|=a<<24-(r+i)%4*8}else for(var i=0;o>i;i+=4)e[r+i>>>2]=n[i>>>2];return this.sigBytes+=o,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=o.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n,r=[],o=function(e){var e=e,n=987654321,r=4294967295;return function(){n=36969*(65535&n)+(n>>16)&r,e=18e3*(65535&e)+(e>>16)&r;var o=(n<<16)+e&r;return o/=4294967296,o+=.5,o*(t.random()>.5?1:-1)}},a=0;e>a;a+=4){var s=o(4294967296*(n||t.random()));n=987654071*s(),r.push(4294967296*s()|0)}return new i.init(r,e)}}),a=n.enc={},s=a.Hex={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push((i>>>4).toString(16)),r.push((15&i).toString(16))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r+=2)n[r>>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new i.init(n,e/2)}},u=a.Latin1={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push(String.fromCharCode(i))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r++)n[r>>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new i.init(n,e)}},c=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},l=r.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new i.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=c.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,o=n.sigBytes,a=this.blockSize,s=4*a,u=o/s;u=e?t.ceil(u):t.max((0|u)-this._minBufferSize,0);var c=u*a,l=t.min(4*c,o);if(c){for(var p=0;c>p;p+=a)this._doProcessBlock(r,p);var f=r.splice(0,c);n.sigBytes-=l}return new i.init(f,l)},clone:function(){var t=o.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),p=(r.Hasher=l.extend({cfg:o.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){l.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},blockSize:16,_createHelper:function(t){return function(e,n){return new t.init(n).finalize(e)}},_createHmacHelper:function(t){return function(e,n){return new p.HMAC.init(t,n).finalize(e)}}}),n.algo={});return n}(Math);return t})},{}],34:[function(t,e,n){!function(r,o,i){"object"==typeof n?e.exports=n=o(t("./core"),t("./x64-core")):"function"==typeof define&&define.amd?define(["./core","./x64-core"],o):o(r.CryptoJS)}(this,function(t){return function(e){var n=t,r=n.lib,o=r.WordArray,i=r.Hasher,a=n.x64,s=a.Word,u=n.algo,c=[],l=[],p=[];!function(){for(var t=1,e=0,n=0;24>n;n++){c[t+5*e]=(n+1)*(n+2)/2%64;var r=e%5,o=(2*t+3*e)%5;t=r,e=o}for(var t=0;5>t;t++)for(var e=0;5>e;e++)l[t+5*e]=e+(2*t+3*e)%5*5;for(var i=1,a=0;24>a;a++){for(var u=0,f=0,m=0;7>m;m++){if(1&i){var h=(1<h?f^=1<t;t++)f[t]=s.create()}();var m=u.SHA3=i.extend({cfg:i.cfg.extend({outputLength:512}),_doReset:function(){for(var t=this._state=[],e=0;25>e;e++)t[e]=new s.init;this.blockSize=(1600-2*this.cfg.outputLength)/32},_doProcessBlock:function(t,e){for(var n=this._state,r=this.blockSize/2,o=0;r>o;o++){var i=t[e+2*o],a=t[e+2*o+1];i=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8),a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8);var s=n[o];s.high^=a,s.low^=i}for(var u=0;24>u;u++){for(var m=0;5>m;m++){for(var h=0,d=0,y=0;5>y;y++){var s=n[m+5*y];h^=s.high,d^=s.low}var g=f[m];g.high=h,g.low=d}for(var m=0;5>m;m++)for(var v=f[(m+4)%5],b=f[(m+1)%5],w=b.high,_=b.low,h=v.high^(w<<1|_>>>31),d=v.low^(_<<1|w>>>31),y=0;5>y;y++){var s=n[m+5*y];s.high^=h,s.low^=d}for(var x=1;25>x;x++){var s=n[x],I=s.high,F=s.low,k=c[x];if(32>k)var h=I<>>32-k,d=F<>>32-k;else var h=F<>>64-k,d=I<>>64-k;var B=f[l[x]];B.high=h,B.low=d}var T=f[0],N=n[0];T.high=N.high,T.low=N.low;for(var m=0;5>m;m++)for(var y=0;5>y;y++){var x=m+5*y,s=n[x],P=f[x],O=f[(m+1)%5+5*y],A=f[(m+2)%5+5*y];s.high=P.high^~O.high&A.high,s.low=P.low^~O.low&A.low}var s=n[0],C=p[u];s.high^=C.high,s.low^=C.low}},_doFinalize:function(){var t=this._data,n=t.words,r=(8*this._nDataBytes,8*t.sigBytes),i=32*this.blockSize;n[r>>>5]|=1<<24-r%32,n[(e.ceil((r+1)/i)*i>>>5)-1]|=128,t.sigBytes=4*n.length,this._process();for(var a=this._state,s=this.cfg.outputLength/8,u=s/8,c=[],l=0;u>l;l++){var p=a[l],f=p.high,m=p.low;f=16711935&(f<<8|f>>>24)|4278255360&(f<<24|f>>>8),m=16711935&(m<<8|m>>>24)|4278255360&(m<<24|m>>>8),c.push(m),c.push(f)}return new o.init(c,s)},clone:function(){for(var t=i.clone.call(this),e=t._state=this._state.slice(0),n=0;25>n;n++)e[n]=e[n].clone();return t}});n.SHA3=i._createHelper(m),n.HmacSHA3=i._createHmacHelper(m)}(Math),t.SHA3})},{"./core":33,"./x64-core":35}],35:[function(t,e,n){!function(r,o){"object"==typeof n?e.exports=n=o(t("./core")):"function"==typeof define&&define.amd?define(["./core"],o):o(r.CryptoJS)}(this,function(t){return function(e){{var n=t,r=n.lib,o=r.Base,i=r.WordArray,a=n.x64={};a.Word=o.extend({init:function(t,e){this.high=t,this.low=e}}),a.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:8*t.length},toX32:function(){for(var t=this.words,e=t.length,n=[],r=0;e>r;r++){var o=t[r];n.push(o.high),n.push(o.low)}return i.create(n,this.sigBytes)},clone:function(){for(var t=o.clone.call(this),e=t.words=this.words.slice(0),n=e.length,r=0;n>r;r++)e[r]=e[r].clone();return t}})}}(),t})},{"./core":33}],"bignumber.js":[function(t,e,n){"use strict";e.exports=BigNumber},{}],web3:[function(t,e,n){var r=t("./lib/web3");r.providers.HttpProvider=t("./lib/web3/httpprovider"),r.providers.IpcProvider=t("./lib/web3/ipcprovider"),r.eth.contract=t("./lib/web3/contract"),r.eth.namereg=t("./lib/web3/namereg"),r.eth.sendIBANTransaction=t("./lib/web3/transfer"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/ipcprovider":22,"./lib/web3/namereg":25,"./lib/web3/transfer":30}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/web3.js b/libjsqrc/ethereumjs/dist/web3.js index 402bcd64f..7882ccd81 100644 --- a/libjsqrc/ethereumjs/dist/web3.js +++ b/libjsqrc/ethereumjs/dist/web3.js @@ -1398,7 +1398,7 @@ module.exports = { },{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){ module.exports={ - "version": "0.7.1" + "version": "0.9.0" } },{}],9:[function(require,module,exports){ @@ -1505,6 +1505,9 @@ web3.setProvider = function (provider) { this.currentProvider = provider; RequestManager.getInstance().setProvider(provider); }; +web3.isConnected = function(){ + return (this.currentProvider && this.currentProvider.isConnected()); +}; web3.reset = function () { RequestManager.getInstance().reset(); c.defaultBlock = 'latest'; @@ -1575,7 +1578,7 @@ setupMethods(web3.shh, shh.methods); module.exports = web3; -},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":23,"./web3/net":25,"./web3/property":26,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){ +},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":24,"./web3/net":26,"./web3/property":27,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1620,7 +1623,6 @@ AllSolidityEvents.prototype.encode = function (options) { result[f] = formatters.inputBlockNumberFormatter(options[f]); }); - result.topics = [null, null, null, null, null]; // match all topics result.address = this._address; return result; @@ -1682,6 +1684,8 @@ module.exports = AllSolidityEvents; */ var RequestManager = require('./requestmanager'); +var Jsonrpc = require('./jsonrpc'); +var errors = require('./errors'); var Batch = function () { this.requests = []; @@ -1708,11 +1712,14 @@ Batch.prototype.execute = function () { results = results || []; requests.map(function (request, index) { return results[index] || {}; - }).map(function (result, index) { - return requests[index].format ? requests[index].format(result.result) : result.result; }).forEach(function (result, index) { if (requests[index].callback) { - requests[index].callback(err, result); + + if (!Jsonrpc.getInstance().isValidResponse(result)) { + return requests[index].callback(errors.InvalidResponse(result)); + } + + requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result)); } }); }); @@ -1721,7 +1728,7 @@ Batch.prototype.execute = function () { module.exports = Batch; -},{"./requestmanager":28}],12:[function(require,module,exports){ +},{"./errors":14,"./jsonrpc":23,"./requestmanager":28}],12:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1820,6 +1827,79 @@ var contract = function (abi) { return new ContractFactory(abi); }; +/** + * Should be called to check if the contract gets properly deployed on the blockchain. + * + * @method checkForContractAddress + * @param {Object} contract + * @param {Function} callback + * @returns {Undefined} + */ +var checkForContractAddress = function(contract, abi, callback){ + var count = 0, + callbackFired = false; + + // wait for receipt + var filter = web3.eth.filter('latest', function(e){ + if(!e && !callbackFired) { + count++; + + // console.log('Checking for contract address', count); + + // stop watching after 50 blocks (timeout) + if(count > 50) { + + filter.stopWatching(); + callbackFired = true; + + if(callback) + callback(new Error('Contract transaction couldn\'t be found after 50 blocks')); + else + throw new Error('Contract transaction couldn\'t be found after 50 blocks'); + + + } else { + + web3.eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){ + if(receipt && !callbackFired) { + + web3.eth.getCode(receipt.contractAddress, function(e, code){ + /*jshint maxcomplexity: 5 */ + + if(callbackFired) + return; + + filter.stopWatching(); + callbackFired = true; + + if(code.length > 2) { + + // console.log('Contract code deployed!'); + + contract.address = receipt.contractAddress; + + // attach events and methods + addFunctionsToContract(contract, abi); + addEventsToContract(contract, abi); + + // call callback for the second time + if(callback) + callback(null, contract); + + } else { + if(callback) + callback(new Error('The contract code couldn\'t be stored, please check your gas amount.')); + else + throw new Error('The contract code couldn\'t be stored, please check your gas amount.'); + } + }); + } + }); + } + } + }); +}; + /** * Should be called to create new ContractFactory instance * @@ -1838,10 +1918,12 @@ var ContractFactory = function (abi) { * @param {Any} contract constructor param2 (optional) * @param {Object} contract transaction object (required) * @param {Function} callback - * @returns {Contract} returns contract if no callback was passed, - * otherwise calls callback function (err, contract) + * @returns {Contract} returns contract instance */ ContractFactory.prototype.new = function () { + var _this = this; + var contract = new Contract(this.abi); + // parse arguments var options = {}; // required! var callback; @@ -1861,18 +1943,31 @@ ContractFactory.prototype.new = function () { var bytes = encodeConstructorParams(this.abi, args); options.data += bytes; - if (!callback) { - var address = web3.eth.sendTransaction(options); - return this.at(address); + + if(callback) { + + // wait for the contract address adn check if the code was deployed + web3.eth.sendTransaction(options, function (err, hash) { + if (err) { + callback(err); + } else { + // add the transaction hash + contract.transactionHash = hash; + + // call callback for the first time + callback(null, contract); + + checkForContractAddress(contract, _this.abi, callback); + } + }); + } else { + var hash = web3.eth.sendTransaction(options); + // add the transaction hash + contract.transactionHash = hash; + checkForContractAddress(contract, _this.abi); } - - var self = this; - web3.eth.sendTransaction(options, function (err, address) { - if (err) { - callback(err); - } - self.at(address, callback); - }); + + return contract; }; /** @@ -1885,12 +1980,17 @@ ContractFactory.prototype.new = function () { * otherwise calls callback function (err, contract) */ ContractFactory.prototype.at = function (address, callback) { + var contract = new Contract(this.abi, address); // TODO: address is required + + // attach functions + addFunctionsToContract(contract, this.abi); + addEventsToContract(contract, this.abi); if (callback) { - callback(null, new Contract(this.abi, address)); + callback(null, contract); } - return new Contract(this.abi, address); + return contract; }; /** @@ -1902,8 +2002,6 @@ ContractFactory.prototype.at = function (address, callback) { */ var Contract = function (abi, address) { this.address = address; - addFunctionsToContract(this, abi); - addEventsToContract(this, abi); }; module.exports = contract; @@ -1967,7 +2065,7 @@ module.exports = { methods: methods }; -},{"./method":23}],14:[function(require,module,exports){ +},{"./method":24}],14:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2001,7 +2099,7 @@ module.exports = { return new Error('Providor not set or invalid'); }, InvalidResponse: function (result){ - var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response'; + var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: '+ result; return new Error(message); } }; @@ -2162,6 +2260,13 @@ var getTransactionFromBlock = new Method({ outputFormatter: formatters.outputTransactionFormatter }); +var getTransactionReceipt = new Method({ + name: 'getTransactionReceipt', + call: 'eth_getTransactionReceipt', + params: 1, + outputFormatter: formatters.outputTransactionReceiptFormatter +}); + var getTransactionCount = new Method({ name: 'getTransactionCount', call: 'eth_getTransactionCount', @@ -2174,7 +2279,7 @@ var sendRawTransaction = new Method({ name: 'sendRawTransaction', call: 'eth_sendRawTransaction', params: 1, - inputFormatter: [] + inputFormatter: [null] }); var sendTransaction = new Method({ @@ -2240,6 +2345,7 @@ var methods = [ getBlockUncleCount, getTransaction, getTransactionFromBlock, + getTransactionReceipt, getTransactionCount, call, estimateGas, @@ -2292,7 +2398,7 @@ module.exports = { }; -},{"../utils/utils":7,"./formatters":18,"./method":23,"./property":26}],16:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":18,"./method":24,"./property":27}],16:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2398,8 +2504,8 @@ SolidityEvent.prototype.encode = function (indexed, options) { result.topics = []; + result.address = this._address; if (!this._anonymous) { - result.address = this._address; result.topics.push('0x' + this.signature()); } @@ -2594,9 +2700,11 @@ var getLogsAtStart = function(self, callback){ callback(err); } - messages.forEach(function (message) { - callback(null, message); - }); + if(utils.isArray(messages)) { + messages.forEach(function (message) { + callback(null, message); + }); + } }); } }; @@ -2798,8 +2906,8 @@ var inputTransactionFormatter = function (options){ * Formats the output of a transaction to its proper values * * @method outputTransactionFormatter - * @param {Object} transaction - * @returns {Object} transaction + * @param {Object} tx + * @returns {Object} */ var outputTransactionFormatter = function (tx){ if(tx.blockNumber !== null) @@ -2813,12 +2921,36 @@ var outputTransactionFormatter = function (tx){ return tx; }; +/** + * Formats the output of a transaction receipt to its proper values + * + * @method outputTransactionReceiptFormatter + * @param {Object} receipt + * @returns {Object} +*/ +var outputTransactionReceiptFormatter = function (receipt){ + if(receipt.blockNumber !== null) + receipt.blockNumber = utils.toDecimal(receipt.blockNumber); + if(receipt.transactionIndex !== null) + receipt.transactionIndex = utils.toDecimal(receipt.transactionIndex); + receipt.cumulativeGasUsed = utils.toDecimal(receipt.cumulativeGasUsed); + receipt.gasUsed = utils.toDecimal(receipt.gasUsed); + + if(utils.isArray(receipt.logs)) { + receipt.logs = receipt.logs.map(function(log){ + return outputLogFormatter(log); + }); + } + + return receipt; +}; + /** * Formats the output of a block to its proper values * * @method outputBlockFormatter - * @param {Object} block object - * @returns {Object} block object + * @param {Object} block + * @returns {Object} */ var outputBlockFormatter = function(block) { @@ -2926,6 +3058,7 @@ module.exports = { inputPostFormatter: inputPostFormatter, outputBigNumberFormatter: outputBigNumberFormatter, outputTransactionFormatter: outputTransactionFormatter, + outputTransactionReceiptFormatter: outputTransactionReceiptFormatter, outputBlockFormatter: outputBlockFormatter, outputLogFormatter: outputLogFormatter, outputPostFormatter: outputPostFormatter @@ -3191,12 +3324,11 @@ module.exports = SolidityFunction; * Marek Kotewicz * Marian Oancea * Fabian Vogelsteller - * @date 2014 + * @date 2015 */ "use strict"; -// resolves the problem for electron/atom shell environments, which use node integration, but have no process variable available var XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line var errors = require('./errors'); @@ -3204,6 +3336,25 @@ var HttpProvider = function (host) { this.host = host || 'http://localhost:8545'; }; +HttpProvider.prototype.isConnected = function() { + var request = new XMLHttpRequest(); + + request.open('POST', this.host, false); + request.setRequestHeader('Content-type','application/json'); + + try { + request.send(JSON.stringify({ + id: 9999999999, + jsonrpc: '2.0', + method: 'net_listening', + params: [] + })); + return true; + } catch(e) { + return false; + } +}; + HttpProvider.prototype.send = function (payload) { var request = new XMLHttpRequest(); @@ -3228,7 +3379,7 @@ HttpProvider.prototype.send = function (payload) { try { result = JSON.parse(result); } catch(e) { - throw errors.InvalidResponse(result); + throw errors.InvalidResponse(request.responseText); } return result; @@ -3244,7 +3395,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { try { result = JSON.parse(result); } catch(e) { - error = errors.InvalidResponse(result); + error = errors.InvalidResponse(request.responseText); } callback(error, result); @@ -3391,6 +3542,219 @@ module.exports = ICAP; You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ +/** @file ipcprovider.js + * @authors: + * Fabian Vogelsteller + * @date 2015 + */ + +"use strict"; + +var utils = require('../utils/utils'); +var errors = require('./errors'); + +var errorTimeout = '{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}'; + + +var IpcProvider = function (path, net) { + var _this = this; + this.responseCallbacks = {}; + this.path = path; + + net = net || require('net'); + + this.connection = net.connect({path: this.path}); + + this.connection.on('error', function(e){ + console.error('IPC Connection Error', e); + _this._timeout(); + }); + + this.connection.on('end', function(){ + _this._timeout(); + }); + + + // LISTEN FOR CONNECTION RESPONSES + this.connection.on('data', function(data) { + /*jshint maxcomplexity: 6 */ + + _this._parseResponse(data.toString()).forEach(function(result){ + + var id = null; + + // get the id which matches the returned id + if(utils.isArray(result)) { + result.forEach(function(load){ + if(_this.responseCallbacks[load.id]) + id = load.id; + }); + } else { + id = result.id; + } + + // fire the callback + if(_this.responseCallbacks[id]) { + _this.responseCallbacks[id](null, result); + delete _this.responseCallbacks[id]; + } + }); + }); +}; + +/** +Will parse the response and make an array out of it. + +@method _parseResponse +@param {String} data +*/ +IpcProvider.prototype._parseResponse = function(data) { + var _this = this, + returnValues = []; + + // DE-CHUNKER + var dechunkedData = data + .replace(/\}\{/g,'}|--|{') // }{ + .replace(/\}\]\[\{/g,'}]|--|[{') // }][{ + .replace(/\}\[\{/g,'}|--|[{') // }[{ + .replace(/\}\]\{/g,'}]|--|{') // }]{ + .split('|--|'); + + dechunkedData.forEach(function(data){ + + // prepend the last chunk + if(_this.lastChunk) + data = _this.lastChunk + data; + + var result = null; + + try { + result = JSON.parse(data); + + } catch(e) { + + _this.lastChunk = data; + + // start timeout to cancel all requests + clearTimeout(_this.lastChunkTimeout); + _this.lastChunkTimeout = setTimeout(function(){ + _this.timeout(); + throw errors.InvalidResponse(data); + }, 1000 * 15); + + return; + } + + // cancel timeout and set chunk to null + clearTimeout(_this.lastChunkTimeout); + _this.lastChunk = null; + + if(result) + returnValues.push(result); + }); + + return returnValues; +}; + + +/** +Get the adds a callback to the responseCallbacks object, +which will be called if a response matching the response Id will arrive. + +@method _addResponseCallback +*/ +IpcProvider.prototype._addResponseCallback = function(payload, callback) { + var id = payload.id || payload[0].id; + var method = payload.method || payload[0].method; + + this.responseCallbacks[id] = callback; + this.responseCallbacks[id].method = method; +}; + +/** +Timeout all requests when the end/error event is fired + +@method _timeout +*/ +IpcProvider.prototype._timeout = function() { + for(var key in this.responseCallbacks) { + if(this.responseCallbacks.hasOwnProperty(key)){ + this.responseCallbacks[key](errorTimeout.replace('__id__', key).replace('__method__', this.responseCallbacks[key].method)); + delete this.responseCallbacks[key]; + } + } +}; + + +/** +Check if the current connection is still valid. + +@method isConnected +*/ +IpcProvider.prototype.isConnected = function() { + var _this = this; + + // try reconnect, when connection is gone + if(!_this.connection.writable) + _this.connection.connect({path: _this.path}); + + return !!this.connection.writable; +}; + +IpcProvider.prototype.send = function (payload) { + + if(this.connection.writeSync) { + var result; + + // try reconnect, when connection is gone + if(!this.connection.writable) + this.connection.connect({path: this.path}); + + var data = this.connection.writeSync(JSON.stringify(payload)); + + try { + result = JSON.parse(data); + } catch(e) { + throw errors.InvalidResponse(data); + } + + return result; + + } else { + throw new Error('You tried to send "'+ payload.method +'" synchronously. Synchronous requests are not supported by the IPC provider.'); + } +}; + +IpcProvider.prototype.sendAsync = function (payload, callback) { + // try reconnect, when connection is gone + if(!this.connection.writable) + this.connection.connect({path: this.path}); + + + this.connection.write(JSON.stringify(payload)); + this._addResponseCallback(payload, callback); +}; + +module.exports = IpcProvider; + + +},{"../utils/utils":7,"./errors":14,"net":32}],23:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ /** @file jsonrpc.js * @authors: * Marek Kotewicz @@ -3467,7 +3831,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) { module.exports = Jsonrpc; -},{}],23:[function(require,module,exports){ +},{}],24:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3564,7 +3928,7 @@ Method.prototype.formatInput = function (args) { * @return {Object} */ Method.prototype.formatOutput = function (result) { - return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; + return this.outputFormatter && result ? this.outputFormatter(result) : result; }; /** @@ -3641,7 +4005,7 @@ Method.prototype.send = function () { module.exports = Method; -},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],24:[function(require,module,exports){ +},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],25:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3689,7 +4053,7 @@ var abi = [ module.exports = contract(abi).at(address); -},{"./contract":12}],25:[function(require,module,exports){ +},{"./contract":12}],26:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3739,7 +4103,7 @@ module.exports = { }; -},{"../utils/utils":7,"./property":26}],26:[function(require,module,exports){ +},{"../utils/utils":7,"./property":27}],27:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3764,6 +4128,7 @@ module.exports = { */ var RequestManager = require('./requestmanager'); +var utils = require('../utils/utils'); var Property = function (options) { this.name = options.name; @@ -3795,6 +4160,19 @@ Property.prototype.formatOutput = function (result) { return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; }; +/** + * Should be used to extract callback from array of arguments. Modifies input param + * + * @method extractCallback + * @param {Array} arguments + * @return {Function|Null} callback, if exists + */ +Property.prototype.extractCallback = function (args) { + if (utils.isFunction(args[args.length - 1])) { + return args.pop(); // modify the args array! + } +}; + /** * Should attach function to method * @@ -3821,7 +4199,10 @@ Property.prototype.attachToObject = function (obj) { return prefix + name.charAt(0).toUpperCase() + name.slice(1); }; - obj[toAsyncName('get', name)] = this.getAsync.bind(this); + var func = this.getAsync.bind(this); + func.request = this.request.bind(this); + + obj[toAsyncName('get', name)] = func; }; /** @@ -3854,45 +4235,27 @@ Property.prototype.getAsync = function (callback) { }); }; -module.exports = Property; - - -},{"./requestmanager":28}],27:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file qtsync.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * @date 2014 +/** + * Should be called to create pure JSONRPC request which can be used in batch request + * + * @method request + * @param {...} params + * @return {Object} jsonrpc request */ - -var QtSyncProvider = function () { -}; - -QtSyncProvider.prototype.send = function (payload) { - var result = navigator.qt.callMethod(JSON.stringify(payload)); - return JSON.parse(result); +Property.prototype.request = function () { + var payload = { + method: this.getter, + params: [], + callback: this.extractCallback(Array.prototype.slice.call(arguments)) + }; + payload.format = this.formatOutput.bind(this); + return payload; }; -module.exports = QtSyncProvider; +module.exports = Property; -},{}],28:[function(require,module,exports){ +},{"../utils/utils":7,"./requestmanager":28}],28:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -4157,7 +4520,7 @@ RequestManager.prototype.poll = function () { module.exports = RequestManager; -},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":22}],29:[function(require,module,exports){ +},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":23}],29:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -4227,7 +4590,7 @@ module.exports = { }; -},{"./formatters":18,"./method":23}],30:[function(require,module,exports){ +},{"./formatters":18,"./method":24}],30:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -4323,7 +4686,7 @@ var deposit = function (from, address, value, client, callback) { module.exports = transfer; -},{"../web3":9,"./contract":12,"./icap":21,"./namereg":24}],31:[function(require,module,exports){ +},{"../web3":9,"./contract":12,"./icap":21,"./namereg":25}],31:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -4439,7 +4802,7 @@ module.exports = { }; -},{"./method":23}],32:[function(require,module,exports){ +},{"./method":24}],32:[function(require,module,exports){ },{}],33:[function(require,module,exports){ ;(function (root, factory) { @@ -8500,8 +8863,10 @@ module.exports = { },{"crypto":32}],"web3":[function(require,module,exports){ var web3 = require('./lib/web3'); + web3.providers.HttpProvider = require('./lib/web3/httpprovider'); -web3.providers.QtSyncProvider = require('./lib/web3/qtsync'); +web3.providers.IpcProvider = require('./lib/web3/ipcprovider'); + web3.eth.contract = require('./lib/web3/contract'); web3.eth.namereg = require('./lib/web3/namereg'); web3.eth.sendIBANTransaction = require('./lib/web3/transfer'); @@ -8514,5 +8879,5 @@ if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { module.exports = web3; -},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/namereg":24,"./lib/web3/qtsync":27,"./lib/web3/transfer":30}]},{},["web3"]) +},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/ipcprovider":22,"./lib/web3/namereg":25,"./lib/web3/transfer":30}]},{},["web3"]) //# sourceMappingURL=web3.js.map diff --git a/libjsqrc/ethereumjs/dist/web3.js.map b/libjsqrc/ethereumjs/dist/web3.js.map index f67aad1c2..1343e68d6 100644 --- a/libjsqrc/ethereumjs/dist/web3.js.map +++ b/libjsqrc/ethereumjs/dist/web3.js.map @@ -23,12 +23,12 @@ "lib/web3/function.js", "lib/web3/httpprovider.js", "lib/web3/icap.js", + "lib/web3/ipcprovider.js", "lib/web3/jsonrpc.js", "lib/web3/method.js", "lib/web3/namereg.js", "lib/web3/net.js", "lib/web3/property.js", - "lib/web3/qtsync.js", "lib/web3/requestmanager.js", "lib/web3/shh.js", "lib/web3/transfer.js", @@ -41,7 +41,7 @@ "index.js" ], "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9fA;AACA;AACA;AACA;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3RA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3OA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClHA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACruBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/SA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3nFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9fA;AACA;AACA;AACA;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3OA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClHA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACruBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/SA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3nFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "generated.js", "sourceRoot": "", "sourcesContent": [ @@ -53,26 +53,26 @@ "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file config.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] config\n * @constructor\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nvar BigNumber = require('bignumber.js');\n\nvar ETH_UNITS = [\n 'wei',\n 'kwei',\n 'Mwei',\n 'Gwei',\n 'szabo',\n 'finney',\n 'femtoether',\n 'picoether',\n 'nanoether',\n 'microether',\n 'milliether',\n 'nano',\n 'micro',\n 'milli',\n 'ether',\n 'grand',\n 'Mether',\n 'Gether',\n 'Tether',\n 'Pether',\n 'Eether',\n 'Zether',\n 'Yether',\n 'Nether',\n 'Dether',\n 'Vether',\n 'Uether'\n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },\n ETH_POLLING_TIMEOUT: 1000/2,\n defaultBlock: 'latest',\n defaultAccount: undefined\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file sha3.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('./utils');\nvar sha3 = require('crypto-js/sha3');\n\nmodule.exports = function (str, isNew) {\n if (str.substr(0, 2) === '0x' && !isNew) {\n console.warn('requirement of using web3.fromAscii before sha3 is deprecated');\n console.warn('new usage: \\'web3.sha3(\"hello\")\\'');\n console.warn('see https://github.com/ethereum/web3.js/pull/205');\n console.warn('if you need to hash hex value, you can do \\'sha3(\"0xfff\", true)\\'');\n str = utils.toAscii(str);\n }\n\n return sha3(str, {\n outputLength: 256\n }).toString();\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file utils.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] utils\n * @constructor\n */\n\nvar BigNumber = require('bignumber.js');\n\nvar unitMap = {\n 'wei': '1',\n 'kwei': '1000',\n 'ada': '1000',\n 'femtoether': '1000',\n 'mwei': '1000000',\n 'babbage': '1000000',\n 'picoether': '1000000',\n 'gwei': '1000000000',\n 'shannon': '1000000000',\n 'nanoether': '1000000000',\n 'nano': '1000000000',\n 'szabo': '1000000000000',\n 'microether': '1000000000000',\n 'micro': '1000000000000',\n 'finney': '1000000000000000',\n 'milliether': '1000000000000000',\n 'milli': '1000000000000000',\n 'ether': '1000000000000000000',\n 'kether': '1000000000000000000000',\n 'grand': '1000000000000000000000',\n 'einstein': '1000000000000000000000',\n 'mether': '1000000000000000000000000',\n 'gether': '1000000000000000000000000000',\n 'tether': '1000000000000000000000000000000'\n};\n\n/**\n * Should be called to pad string to expected length\n *\n * @method padLeft\n * @param {String} string to be padded\n * @param {Number} characters that result string should have\n * @param {String} sign, by default 0\n * @returns {String} right aligned string\n */\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/**\n * Should be called to pad string to expected length\n *\n * @method padRight\n * @param {String} string to be padded\n * @param {Number} characters that result string should have\n * @param {String} sign, by default 0\n * @returns {String} right aligned string\n */\nvar padRight = function (string, chars, sign) {\n return string + (new Array(chars - string.length + 1).join(sign ? sign : \"0\"));\n};\n\n/** \n * Should be called to get sting from it's hex representation\n *\n * @method toAscii\n * @param {String} string in hex\n * @returns {String} ascii string representation of hex value\n */\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method toHexNative\n * @param {String} string\n * @returns {String} hex representation of input string\n */\nvar toHexNative = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @param {Number} optional padding\n * @returns {String} hex representation of input string\n */\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHexNative(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/**\n * Should be used to create full function/event name from json abi\n *\n * @method transformToFullName\n * @param {Object} json-abi\n * @return {String} full fnction/event name\n */\nvar transformToFullName = function (json) {\n if (json.name.indexOf('(') !== -1) {\n return json.name;\n }\n\n var typeName = json.inputs.map(function(i){return i.type; }).join();\n return json.name + '(' + typeName + ')';\n};\n\n/**\n * Should be called to get display name of contract function\n * \n * @method extractDisplayName\n * @param {String} name of function/event\n * @returns {String} display name for function/event eg. multiply(uint256) -> multiply\n */\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/**\n * Converts value to it's decimal representation in string\n *\n * @method toDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar toDecimal = function (value) {\n return toBigNumber(value).toNumber();\n};\n\n/**\n * Converts value to it's hex representation\n *\n * @method fromDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar fromDecimal = function (value) {\n var number = toBigNumber(value);\n var result = number.toString(16);\n\n return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result;\n};\n\n/**\n * Auto converts any given value into it's hex representation.\n *\n * And even stringifys objects before.\n *\n * @method toHex\n * @param {String|Number|BigNumber|Object}\n * @return {String}\n */\nvar toHex = function (val) {\n /*jshint maxcomplexity: 8 */\n\n if (isBoolean(val))\n return fromDecimal(+val);\n\n if (isBigNumber(val))\n return fromDecimal(val);\n\n if (isObject(val))\n return fromAscii(JSON.stringify(val));\n\n // if its a negative number, pass it through fromDecimal\n if (isString(val)) {\n if (val.indexOf('-0x') === 0)\n return fromDecimal(val);\n else if (!isFinite(val))\n return fromAscii(val);\n else if(val.indexOf('0x') === 0)\n return val;\n }\n\n return fromDecimal(val);\n};\n\n/**\n * Returns value of unit in Wei\n *\n * @method getValueOfUnit\n * @param {String} unit the unit to convert to, default ether\n * @returns {BigNumber} value of the unit (in Wei)\n * @throws error if the unit is not correct:w\n */\nvar getValueOfUnit = function (unit) {\n unit = unit ? unit.toLowerCase() : 'ether';\n var unitValue = unitMap[unit];\n if (unitValue === undefined) {\n throw new Error('This unit doesn\\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2));\n }\n return new BigNumber(unitValue, 10);\n};\n\n/**\n * Takes a number of wei and converts it to any other ether unit.\n *\n * Possible units are:\n * SI Short SI Full Effigy Other\n * - kwei femtoether ada\n * - mwei picoether babbage\n * - gwei nanoether shannon nano\n * - -- microether szabo micro\n * - -- milliether finney milli\n * - ether -- --\n * - kether einstein grand \n * - mether\n * - gether\n * - tether\n *\n * @method fromWei\n * @param {Number|String} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert to, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar fromWei = function(number, unit) {\n var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes a number of a unit and converts it to wei.\n *\n * Possible units are:\n * SI Short SI Full Effigy Other\n * - kwei femtoether ada\n * - mwei picoether babbage \n * - gwei nanoether shannon nano\n * - -- microether szabo micro\n * - -- milliether finney milli\n * - ether -- --\n * - kether einstein grand \n * - mether\n * - gether\n * - tether\n *\n * @method toWei\n * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert from, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar toWei = function(number, unit) {\n var returnValue = toBigNumber(number).times(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes an input and transforms it into an bignumber\n *\n * @method toBigNumber\n * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber\n * @return {BigNumber} BigNumber\n*/\nvar toBigNumber = function(number) {\n /*jshint maxcomplexity:5 */\n number = number || 0;\n if (isBigNumber(number))\n return number;\n\n if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {\n return new BigNumber(number.replace('0x',''), 16);\n }\n \n return new BigNumber(number.toString(10), 10);\n};\n\n/**\n * Takes and input transforms it into bignumber and if it is negative value, into two's complement\n *\n * @method toTwosComplement\n * @param {Number|String|BigNumber}\n * @return {BigNumber}\n */\nvar toTwosComplement = function (number) {\n var bigNumber = toBigNumber(number);\n if (bigNumber.lessThan(0)) {\n return new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(bigNumber).plus(1);\n }\n return bigNumber;\n};\n\n/**\n * Checks if the given string is strictly an address\n *\n * @method isStrictAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isStrictAddress = function (address) {\n return /^0x[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Checks if the given string is an address\n *\n * @method isAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isAddress = function (address) {\n return /^(0x)?[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Transforms given string to valid 20 bytes-length addres with 0x prefix\n *\n * @method toAddress\n * @param {String} address\n * @return {String} formatted address\n */\nvar toAddress = function (address) {\n if (isStrictAddress(address)) {\n return address;\n }\n \n if (/^[0-9a-f]{40}$/.test(address)) {\n return '0x' + address;\n }\n\n return '0x' + padLeft(toHex(address).substr(2), 40);\n};\n\n\n/**\n * Returns true if object is BigNumber, otherwise false\n *\n * @method isBigNumber\n * @param {Object}\n * @return {Boolean} \n */\nvar isBigNumber = function (object) {\n return object instanceof BigNumber ||\n (object && object.constructor && object.constructor.name === 'BigNumber');\n};\n\n/**\n * Returns true if object is string, otherwise false\n * \n * @method isString\n * @param {Object}\n * @return {Boolean}\n */\nvar isString = function (object) {\n return typeof object === 'string' ||\n (object && object.constructor && object.constructor.name === 'String');\n};\n\n/**\n * Returns true if object is function, otherwise false\n *\n * @method isFunction\n * @param {Object}\n * @return {Boolean}\n */\nvar isFunction = function (object) {\n return typeof object === 'function';\n};\n\n/**\n * Returns true if object is Objet, otherwise false\n *\n * @method isObject\n * @param {Object}\n * @return {Boolean}\n */\nvar isObject = function (object) {\n return typeof object === 'object';\n};\n\n/**\n * Returns true if object is boolean, otherwise false\n *\n * @method isBoolean\n * @param {Object}\n * @return {Boolean}\n */\nvar isBoolean = function (object) {\n return typeof object === 'boolean';\n};\n\n/**\n * Returns true if object is array, otherwise false\n *\n * @method isArray\n * @param {Object}\n * @return {Boolean}\n */\nvar isArray = function (object) {\n return object instanceof Array; \n};\n\n/**\n * Returns true if given string is valid json object\n * \n * @method isJson\n * @param {String}\n * @return {Boolean}\n */\nvar isJson = function (str) {\n try {\n return !!JSON.parse(str);\n } catch (e) {\n return false;\n }\n};\n\n/**\n * This method should be called to check if string is valid ethereum IBAN number\n * Supports direct and indirect IBANs\n *\n * @method isIBAN\n * @param {String}\n * @return {Boolean}\n */\nvar isIBAN = function (iban) {\n return /^XE[0-9]{2}(ETH[0-9A-Z]{13}|[0-9A-Z]{30})$/.test(iban);\n};\n\nmodule.exports = {\n padLeft: padLeft,\n padRight: padRight,\n toHex: toHex,\n toDecimal: toDecimal,\n fromDecimal: fromDecimal,\n toAscii: toAscii,\n fromAscii: fromAscii,\n transformToFullName: transformToFullName,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n toWei: toWei,\n fromWei: fromWei,\n toBigNumber: toBigNumber,\n toTwosComplement: toTwosComplement,\n toAddress: toAddress,\n isBigNumber: isBigNumber,\n isStrictAddress: isStrictAddress,\n isAddress: isAddress,\n isFunction: isFunction,\n isString: isString,\n isObject: isObject,\n isBoolean: isBoolean,\n isArray: isArray,\n isJson: isJson,\n isIBAN: isIBAN\n};\n\n", - "module.exports={\n \"version\": \"0.7.1\"\n}\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar version = require('./version.json');\nvar net = require('./web3/net');\nvar eth = require('./web3/eth');\nvar db = require('./web3/db');\nvar shh = require('./web3/shh');\nvar watches = require('./web3/watches');\nvar Filter = require('./web3/filter');\nvar utils = require('./utils/utils');\nvar formatters = require('./web3/formatters');\nvar RequestManager = require('./web3/requestmanager');\nvar c = require('./utils/config');\nvar Property = require('./web3/property');\nvar Batch = require('./web3/batch');\nvar sha3 = require('./utils/sha3');\n\nvar web3Properties = [\n new Property({\n name: 'version.client',\n getter: 'web3_clientVersion'\n }),\n new Property({\n name: 'version.network',\n getter: 'net_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.ethereum',\n getter: 'eth_protocolVersion',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.whisper',\n getter: 'shh_version',\n inputFormatter: utils.toDecimal\n })\n];\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n method.attachToObject(obj);\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n property.attachToObject(obj);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {};\nweb3.providers = {};\nweb3.currentProvider = null;\nweb3.version = {};\nweb3.version.api = version.version;\nweb3.eth = {};\n\n/*jshint maxparams:4 */\nweb3.eth.filter = function (fil, callback) {\n return new Filter(fil, watches.eth(), formatters.outputLogFormatter, callback);\n};\n/*jshint maxparams:3 */\n\nweb3.shh = {};\nweb3.shh.filter = function (fil, callback) {\n return new Filter(fil, watches.shh(), formatters.outputPostFormatter, callback);\n};\nweb3.net = {};\nweb3.db = {};\nweb3.setProvider = function (provider) {\n this.currentProvider = provider;\n RequestManager.getInstance().setProvider(provider);\n};\nweb3.reset = function () {\n RequestManager.getInstance().reset();\n c.defaultBlock = 'latest';\n c.defaultAccount = undefined;\n};\nweb3.toHex = utils.toHex;\nweb3.toAscii = utils.toAscii;\nweb3.fromAscii = utils.fromAscii;\nweb3.toDecimal = utils.toDecimal;\nweb3.fromDecimal = utils.fromDecimal;\nweb3.toBigNumber = utils.toBigNumber;\nweb3.toWei = utils.toWei;\nweb3.fromWei = utils.fromWei;\nweb3.isAddress = utils.isAddress;\nweb3.isIBAN = utils.isIBAN;\nweb3.sha3 = sha3;\nweb3.createBatch = function () {\n return new Batch();\n};\n\n// ADD defaultblock\nObject.defineProperty(web3.eth, 'defaultBlock', {\n get: function () {\n return c.defaultBlock;\n },\n set: function (val) {\n c.defaultBlock = val;\n return val;\n }\n});\n\nObject.defineProperty(web3.eth, 'defaultAccount', {\n get: function () {\n return c.defaultAccount;\n },\n set: function (val) {\n c.defaultAccount = val;\n return val;\n }\n});\n\n\n// EXTEND\nweb3._extend = function(extension){\n /*jshint maxcomplexity: 6 */\n\n if(extension.property && !web3[extension.property])\n web3[extension.property] = {};\n\n setupMethods(web3[extension.property] || web3, extension.methods || []);\n setupProperties(web3[extension.property] || web3, extension.properties || []);\n};\nweb3._extend.formatters = formatters;\nweb3._extend.utils = utils;\nweb3._extend.Method = require('./web3/method');\nweb3._extend.Property = require('./web3/property');\n\n\n/// setups all api methods\nsetupProperties(web3, web3Properties);\nsetupMethods(web3.net, net.methods);\nsetupProperties(web3.net, net.properties);\nsetupMethods(web3.eth, eth.methods);\nsetupProperties(web3.eth, eth.properties);\nsetupMethods(web3.db, db.methods);\nsetupMethods(web3.shh, shh.methods);\n\nmodule.exports = web3;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file allevents.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar sha3 = require('../utils/sha3');\nvar SolidityEvent = require('./event');\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Filter = require('./filter');\nvar watches = require('./watches');\n\nvar AllSolidityEvents = function (json, address) {\n this._json = json;\n this._address = address;\n};\n\nAllSolidityEvents.prototype.encode = function (options) {\n options = options || {};\n var result = {};\n\n ['fromBlock', 'toBlock'].filter(function (f) {\n return options[f] !== undefined;\n }).forEach(function (f) {\n result[f] = formatters.inputBlockNumberFormatter(options[f]);\n });\n\n result.topics = [null, null, null, null, null]; // match all topics\n result.address = this._address;\n\n return result;\n};\n\nAllSolidityEvents.prototype.decode = function (data) {\n data.data = data.data || '';\n data.topics = data.topics || [];\n\n var eventTopic = data.topics[0].slice(2);\n var match = this._json.filter(function (j) {\n return eventTopic === sha3(utils.transformToFullName(j));\n })[0];\n\n if (!match) { // cannot find matching event?\n console.warn('cannot find event for log');\n return data;\n }\n\n var event = new SolidityEvent(match, this._address);\n return event.decode(data);\n};\n\nAllSolidityEvents.prototype.execute = function (options, callback) {\n var o = this.encode(options);\n var formatter = this.decode.bind(this);\n return new Filter(o, watches.eth(), formatter, callback);\n};\n\nAllSolidityEvents.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n contract.allEvents = execute;\n};\n\nmodule.exports = AllSolidityEvents;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file batch.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\n\nvar Batch = function () {\n this.requests = [];\n};\n\n/**\n * Should be called to add create new request to batch request\n *\n * @method add\n * @param {Object} jsonrpc requet object\n */\nBatch.prototype.add = function (request) {\n this.requests.push(request);\n};\n\n/**\n * Should be called to execute batch request\n *\n * @method execute\n */\nBatch.prototype.execute = function () {\n var requests = this.requests;\n RequestManager.getInstance().sendBatch(requests, function (err, results) {\n results = results || [];\n requests.map(function (request, index) {\n return results[index] || {};\n }).map(function (result, index) {\n return requests[index].format ? requests[index].format(result.result) : result.result;\n }).forEach(function (result, index) {\n if (requests[index].callback) {\n requests[index].callback(err, result);\n }\n });\n }); \n};\n\nmodule.exports = Batch;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file contract.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('../web3'); \nvar utils = require('../utils/utils');\nvar coder = require('../solidity/coder');\nvar SolidityEvent = require('./event');\nvar SolidityFunction = require('./function');\nvar AllEvents = require('./allevents');\n\n/**\n * Should be called to encode constructor params\n *\n * @method encodeConstructorParams\n * @param {Array} abi\n * @param {Array} constructor params\n */\nvar encodeConstructorParams = function (abi, params) {\n return abi.filter(function (json) {\n return json.type === 'constructor' && json.inputs.length === params.length;\n }).map(function (json) {\n return json.inputs.map(function (input) {\n return input.type;\n });\n }).map(function (types) {\n return coder.encodeParams(types, params);\n })[0] || '';\n};\n\n/**\n * Should be called to add functions to contract object\n *\n * @method addFunctionsToContract\n * @param {Contract} contract\n * @param {Array} abi\n */\nvar addFunctionsToContract = function (contract, abi) {\n abi.filter(function (json) {\n return json.type === 'function';\n }).map(function (json) {\n return new SolidityFunction(json, contract.address);\n }).forEach(function (f) {\n f.attachToContract(contract);\n });\n};\n\n/**\n * Should be called to add events to contract object\n *\n * @method addEventsToContract\n * @param {Contract} contract\n * @param {Array} abi\n */\nvar addEventsToContract = function (contract, abi) {\n var events = abi.filter(function (json) {\n return json.type === 'event';\n });\n\n var All = new AllEvents(events, contract.address);\n All.attachToContract(contract);\n \n events.map(function (json) {\n return new SolidityEvent(json, contract.address);\n }).forEach(function (e) {\n e.attachToContract(contract);\n });\n};\n\n/**\n * Should be called to create new ContractFactory\n *\n * @method contract\n * @param {Array} abi\n * @returns {ContractFactory} new contract factory\n */\nvar contract = function (abi) {\n return new ContractFactory(abi);\n};\n\n/**\n * Should be called to create new ContractFactory instance\n *\n * @method ContractFactory\n * @param {Array} abi\n */\nvar ContractFactory = function (abi) {\n this.abi = abi;\n};\n\n/**\n * Should be called to create new contract on a blockchain\n * \n * @method new\n * @param {Any} contract constructor param1 (optional)\n * @param {Any} contract constructor param2 (optional)\n * @param {Object} contract transaction object (required)\n * @param {Function} callback\n * @returns {Contract} returns contract if no callback was passed,\n * otherwise calls callback function (err, contract)\n */\nContractFactory.prototype.new = function () {\n // parse arguments\n var options = {}; // required!\n var callback;\n\n var args = Array.prototype.slice.call(arguments);\n if (utils.isFunction(args[args.length - 1])) {\n callback = args.pop();\n }\n\n var last = args[args.length - 1];\n if (utils.isObject(last) && !utils.isArray(last)) {\n options = args.pop();\n }\n\n // throw an error if there are no options\n\n var bytes = encodeConstructorParams(this.abi, args);\n options.data += bytes;\n\n if (!callback) {\n var address = web3.eth.sendTransaction(options);\n return this.at(address);\n }\n \n var self = this;\n web3.eth.sendTransaction(options, function (err, address) {\n if (err) {\n callback(err);\n }\n self.at(address, callback); \n }); \n};\n\n/**\n * Should be called to get access to existing contract on a blockchain\n *\n * @method at\n * @param {Address} contract address (required)\n * @param {Function} callback {optional)\n * @returns {Contract} returns contract if no callback was passed,\n * otherwise calls callback function (err, contract)\n */\nContractFactory.prototype.at = function (address, callback) {\n // TODO: address is required\n \n if (callback) {\n callback(null, new Contract(this.abi, address));\n } \n return new Contract(this.abi, address);\n};\n\n/**\n * Should be called to create new contract instance\n *\n * @method Contract\n * @param {Array} abi\n * @param {Address} contract address\n */\nvar Contract = function (abi, address) {\n this.address = address;\n addFunctionsToContract(this, abi);\n addEventsToContract(this, abi);\n};\n\nmodule.exports = contract;\n\n", + "module.exports={\n \"version\": \"0.9.0\"\n}\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar version = require('./version.json');\nvar net = require('./web3/net');\nvar eth = require('./web3/eth');\nvar db = require('./web3/db');\nvar shh = require('./web3/shh');\nvar watches = require('./web3/watches');\nvar Filter = require('./web3/filter');\nvar utils = require('./utils/utils');\nvar formatters = require('./web3/formatters');\nvar RequestManager = require('./web3/requestmanager');\nvar c = require('./utils/config');\nvar Property = require('./web3/property');\nvar Batch = require('./web3/batch');\nvar sha3 = require('./utils/sha3');\n\nvar web3Properties = [\n new Property({\n name: 'version.client',\n getter: 'web3_clientVersion'\n }),\n new Property({\n name: 'version.network',\n getter: 'net_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.ethereum',\n getter: 'eth_protocolVersion',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.whisper',\n getter: 'shh_version',\n inputFormatter: utils.toDecimal\n })\n];\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n method.attachToObject(obj);\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n property.attachToObject(obj);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {};\nweb3.providers = {};\nweb3.currentProvider = null;\nweb3.version = {};\nweb3.version.api = version.version;\nweb3.eth = {};\n\n/*jshint maxparams:4 */\nweb3.eth.filter = function (fil, callback) {\n return new Filter(fil, watches.eth(), formatters.outputLogFormatter, callback);\n};\n/*jshint maxparams:3 */\n\nweb3.shh = {};\nweb3.shh.filter = function (fil, callback) {\n return new Filter(fil, watches.shh(), formatters.outputPostFormatter, callback);\n};\nweb3.net = {};\nweb3.db = {};\nweb3.setProvider = function (provider) {\n this.currentProvider = provider;\n RequestManager.getInstance().setProvider(provider);\n};\nweb3.isConnected = function(){\n return (this.currentProvider && this.currentProvider.isConnected());\n};\nweb3.reset = function () {\n RequestManager.getInstance().reset();\n c.defaultBlock = 'latest';\n c.defaultAccount = undefined;\n};\nweb3.toHex = utils.toHex;\nweb3.toAscii = utils.toAscii;\nweb3.fromAscii = utils.fromAscii;\nweb3.toDecimal = utils.toDecimal;\nweb3.fromDecimal = utils.fromDecimal;\nweb3.toBigNumber = utils.toBigNumber;\nweb3.toWei = utils.toWei;\nweb3.fromWei = utils.fromWei;\nweb3.isAddress = utils.isAddress;\nweb3.isIBAN = utils.isIBAN;\nweb3.sha3 = sha3;\nweb3.createBatch = function () {\n return new Batch();\n};\n\n// ADD defaultblock\nObject.defineProperty(web3.eth, 'defaultBlock', {\n get: function () {\n return c.defaultBlock;\n },\n set: function (val) {\n c.defaultBlock = val;\n return val;\n }\n});\n\nObject.defineProperty(web3.eth, 'defaultAccount', {\n get: function () {\n return c.defaultAccount;\n },\n set: function (val) {\n c.defaultAccount = val;\n return val;\n }\n});\n\n\n// EXTEND\nweb3._extend = function(extension){\n /*jshint maxcomplexity: 6 */\n\n if(extension.property && !web3[extension.property])\n web3[extension.property] = {};\n\n setupMethods(web3[extension.property] || web3, extension.methods || []);\n setupProperties(web3[extension.property] || web3, extension.properties || []);\n};\nweb3._extend.formatters = formatters;\nweb3._extend.utils = utils;\nweb3._extend.Method = require('./web3/method');\nweb3._extend.Property = require('./web3/property');\n\n\n/// setups all api methods\nsetupProperties(web3, web3Properties);\nsetupMethods(web3.net, net.methods);\nsetupProperties(web3.net, net.properties);\nsetupMethods(web3.eth, eth.methods);\nsetupProperties(web3.eth, eth.properties);\nsetupMethods(web3.db, db.methods);\nsetupMethods(web3.shh, shh.methods);\n\nmodule.exports = web3;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file allevents.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar sha3 = require('../utils/sha3');\nvar SolidityEvent = require('./event');\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Filter = require('./filter');\nvar watches = require('./watches');\n\nvar AllSolidityEvents = function (json, address) {\n this._json = json;\n this._address = address;\n};\n\nAllSolidityEvents.prototype.encode = function (options) {\n options = options || {};\n var result = {};\n\n ['fromBlock', 'toBlock'].filter(function (f) {\n return options[f] !== undefined;\n }).forEach(function (f) {\n result[f] = formatters.inputBlockNumberFormatter(options[f]);\n });\n\n result.address = this._address;\n\n return result;\n};\n\nAllSolidityEvents.prototype.decode = function (data) {\n data.data = data.data || '';\n data.topics = data.topics || [];\n\n var eventTopic = data.topics[0].slice(2);\n var match = this._json.filter(function (j) {\n return eventTopic === sha3(utils.transformToFullName(j));\n })[0];\n\n if (!match) { // cannot find matching event?\n console.warn('cannot find event for log');\n return data;\n }\n\n var event = new SolidityEvent(match, this._address);\n return event.decode(data);\n};\n\nAllSolidityEvents.prototype.execute = function (options, callback) {\n var o = this.encode(options);\n var formatter = this.decode.bind(this);\n return new Filter(o, watches.eth(), formatter, callback);\n};\n\nAllSolidityEvents.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n contract.allEvents = execute;\n};\n\nmodule.exports = AllSolidityEvents;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file batch.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\nvar Jsonrpc = require('./jsonrpc');\nvar errors = require('./errors');\n\nvar Batch = function () {\n this.requests = [];\n};\n\n/**\n * Should be called to add create new request to batch request\n *\n * @method add\n * @param {Object} jsonrpc requet object\n */\nBatch.prototype.add = function (request) {\n this.requests.push(request);\n};\n\n/**\n * Should be called to execute batch request\n *\n * @method execute\n */\nBatch.prototype.execute = function () {\n var requests = this.requests;\n RequestManager.getInstance().sendBatch(requests, function (err, results) {\n results = results || [];\n requests.map(function (request, index) {\n return results[index] || {};\n }).forEach(function (result, index) {\n if (requests[index].callback) {\n\n if (!Jsonrpc.getInstance().isValidResponse(result)) {\n return requests[index].callback(errors.InvalidResponse(result));\n }\n\n requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result));\n }\n });\n }); \n};\n\nmodule.exports = Batch;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file contract.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('../web3'); \nvar utils = require('../utils/utils');\nvar coder = require('../solidity/coder');\nvar SolidityEvent = require('./event');\nvar SolidityFunction = require('./function');\nvar AllEvents = require('./allevents');\n\n/**\n * Should be called to encode constructor params\n *\n * @method encodeConstructorParams\n * @param {Array} abi\n * @param {Array} constructor params\n */\nvar encodeConstructorParams = function (abi, params) {\n return abi.filter(function (json) {\n return json.type === 'constructor' && json.inputs.length === params.length;\n }).map(function (json) {\n return json.inputs.map(function (input) {\n return input.type;\n });\n }).map(function (types) {\n return coder.encodeParams(types, params);\n })[0] || '';\n};\n\n/**\n * Should be called to add functions to contract object\n *\n * @method addFunctionsToContract\n * @param {Contract} contract\n * @param {Array} abi\n */\nvar addFunctionsToContract = function (contract, abi) {\n abi.filter(function (json) {\n return json.type === 'function';\n }).map(function (json) {\n return new SolidityFunction(json, contract.address);\n }).forEach(function (f) {\n f.attachToContract(contract);\n });\n};\n\n/**\n * Should be called to add events to contract object\n *\n * @method addEventsToContract\n * @param {Contract} contract\n * @param {Array} abi\n */\nvar addEventsToContract = function (contract, abi) {\n var events = abi.filter(function (json) {\n return json.type === 'event';\n });\n\n var All = new AllEvents(events, contract.address);\n All.attachToContract(contract);\n \n events.map(function (json) {\n return new SolidityEvent(json, contract.address);\n }).forEach(function (e) {\n e.attachToContract(contract);\n });\n};\n\n/**\n * Should be called to create new ContractFactory\n *\n * @method contract\n * @param {Array} abi\n * @returns {ContractFactory} new contract factory\n */\nvar contract = function (abi) {\n return new ContractFactory(abi);\n};\n\n/**\n * Should be called to check if the contract gets properly deployed on the blockchain.\n *\n * @method checkForContractAddress\n * @param {Object} contract\n * @param {Function} callback\n * @returns {Undefined}\n */\nvar checkForContractAddress = function(contract, abi, callback){\n var count = 0,\n callbackFired = false;\n\n // wait for receipt\n var filter = web3.eth.filter('latest', function(e){\n if(!e && !callbackFired) {\n count++;\n\n // console.log('Checking for contract address', count);\n\n // stop watching after 50 blocks (timeout)\n if(count > 50) {\n \n filter.stopWatching();\n callbackFired = true;\n\n if(callback)\n callback(new Error('Contract transaction couldn\\'t be found after 50 blocks'));\n else\n throw new Error('Contract transaction couldn\\'t be found after 50 blocks');\n\n\n } else {\n\n web3.eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){\n if(receipt && !callbackFired) {\n\n web3.eth.getCode(receipt.contractAddress, function(e, code){\n /*jshint maxcomplexity: 5 */\n\n if(callbackFired)\n return;\n \n filter.stopWatching();\n callbackFired = true;\n\n if(code.length > 2) {\n\n // console.log('Contract code deployed!');\n\n contract.address = receipt.contractAddress;\n\n // attach events and methods\n addFunctionsToContract(contract, abi);\n addEventsToContract(contract, abi);\n\n // call callback for the second time\n if(callback)\n callback(null, contract);\n\n } else {\n if(callback)\n callback(new Error('The contract code couldn\\'t be stored, please check your gas amount.'));\n else\n throw new Error('The contract code couldn\\'t be stored, please check your gas amount.');\n }\n });\n }\n });\n }\n }\n });\n};\n\n/**\n * Should be called to create new ContractFactory instance\n *\n * @method ContractFactory\n * @param {Array} abi\n */\nvar ContractFactory = function (abi) {\n this.abi = abi;\n};\n\n/**\n * Should be called to create new contract on a blockchain\n * \n * @method new\n * @param {Any} contract constructor param1 (optional)\n * @param {Any} contract constructor param2 (optional)\n * @param {Object} contract transaction object (required)\n * @param {Function} callback\n * @returns {Contract} returns contract instance\n */\nContractFactory.prototype.new = function () {\n var _this = this;\n var contract = new Contract(this.abi);\n\n // parse arguments\n var options = {}; // required!\n var callback;\n\n var args = Array.prototype.slice.call(arguments);\n if (utils.isFunction(args[args.length - 1])) {\n callback = args.pop();\n }\n\n var last = args[args.length - 1];\n if (utils.isObject(last) && !utils.isArray(last)) {\n options = args.pop();\n }\n\n // throw an error if there are no options\n\n var bytes = encodeConstructorParams(this.abi, args);\n options.data += bytes;\n\n\n if(callback) {\n\n // wait for the contract address adn check if the code was deployed\n web3.eth.sendTransaction(options, function (err, hash) {\n if (err) {\n callback(err);\n } else {\n // add the transaction hash\n contract.transactionHash = hash;\n\n // call callback for the first time\n callback(null, contract);\n\n checkForContractAddress(contract, _this.abi, callback);\n }\n });\n } else {\n var hash = web3.eth.sendTransaction(options);\n // add the transaction hash\n contract.transactionHash = hash;\n checkForContractAddress(contract, _this.abi);\n }\n\n return contract;\n};\n\n/**\n * Should be called to get access to existing contract on a blockchain\n *\n * @method at\n * @param {Address} contract address (required)\n * @param {Function} callback {optional)\n * @returns {Contract} returns contract if no callback was passed,\n * otherwise calls callback function (err, contract)\n */\nContractFactory.prototype.at = function (address, callback) {\n var contract = new Contract(this.abi, address);\n // TODO: address is required\n\n // attach functions\n addFunctionsToContract(contract, this.abi);\n addEventsToContract(contract, this.abi);\n \n if (callback) {\n callback(null, contract);\n } \n return contract;\n};\n\n/**\n * Should be called to create new contract instance\n *\n * @method Contract\n * @param {Array} abi\n * @param {Address} contract address\n */\nvar Contract = function (abi, address) {\n this.address = address;\n};\n\nmodule.exports = contract;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file db.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\nvar putString = new Method({\n name: 'putString',\n call: 'db_putString',\n params: 3\n});\n\n\nvar getString = new Method({\n name: 'getString',\n call: 'db_getString',\n params: 2\n});\n\nvar putHex = new Method({\n name: 'putHex',\n call: 'db_putHex',\n params: 3\n});\n\nvar getHex = new Method({\n name: 'getHex',\n call: 'db_getHex',\n params: 2\n});\n\nvar methods = [\n putString, getString, putHex, getHex\n];\n\nmodule.exports = {\n methods: methods\n};\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file errors.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nmodule.exports = {\n InvalidNumberOfParams: function () {\n return new Error('Invalid number of input parameters');\n },\n InvalidConnection: function (host){\n return new Error('CONNECTION ERROR: Couldn\\'t connect to node '+ host +', is it running?');\n },\n InvalidProvider: function () {\n return new Error('Providor not set or invalid');\n },\n InvalidResponse: function (result){\n var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response';\n return new Error(message);\n }\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file eth.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\n/**\n * Web3\n *\n * @module web3\n */\n\n/**\n * Eth methods and properties\n *\n * An example method object can look as follows:\n *\n * {\n * name: 'getBlock',\n * call: blockCall,\n * params: 2,\n * outputFormatter: formatters.outputBlockFormatter,\n * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter\n * utils.toHex, // formats paramter 1\n * function(param){ return !!param; } // formats paramter 2\n * ]\n * },\n *\n * @class [web3] eth\n * @constructor\n */\n\n\"use strict\";\n\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Method = require('./method');\nvar Property = require('./property');\n\nvar blockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? \"eth_getBlockByHash\" : \"eth_getBlockByNumber\";\n};\n\nvar transactionFromBlockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';\n};\n\nvar uncleCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';\n};\n\nvar getBlockTransactionCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';\n};\n\nvar uncleCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';\n};\n\n/// @returns an array of objects describing web3.eth api methods\n\nvar getBalance = new Method({\n name: 'getBalance',\n call: 'eth_getBalance',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: formatters.outputBigNumberFormatter\n});\n\nvar getStorageAt = new Method({\n name: 'getStorageAt',\n call: 'eth_getStorageAt',\n params: 3,\n inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getCode = new Method({\n name: 'getCode',\n call: 'eth_getCode',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getBlock = new Method({\n name: 'getBlock',\n call: blockCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter\n});\n\nvar getUncle = new Method({\n name: 'getUncle',\n call: uncleCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],\n outputFormatter: formatters.outputBlockFormatter,\n\n});\n\nvar getCompilers = new Method({\n name: 'getCompilers',\n call: 'eth_getCompilers',\n params: 0\n});\n\nvar getBlockTransactionCount = new Method({\n name: 'getBlockTransactionCount',\n call: getBlockTransactionCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getBlockUncleCount = new Method({\n name: 'getBlockUncleCount',\n call: uncleCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getTransaction = new Method({\n name: 'getTransaction',\n call: 'eth_getTransactionByHash',\n params: 1,\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionFromBlock = new Method({\n name: 'getTransactionFromBlock',\n call: transactionFromBlockCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionCount = new Method({\n name: 'getTransactionCount',\n call: 'eth_getTransactionCount',\n params: 2,\n inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar sendRawTransaction = new Method({\n name: 'sendRawTransaction',\n call: 'eth_sendRawTransaction',\n params: 1,\n inputFormatter: []\n});\n\nvar sendTransaction = new Method({\n name: 'sendTransaction',\n call: 'eth_sendTransaction',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter]\n});\n\nvar call = new Method({\n name: 'call',\n call: 'eth_call',\n params: 2,\n inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar estimateGas = new Method({\n name: 'estimateGas',\n call: 'eth_estimateGas',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar compileSolidity = new Method({\n name: 'compile.solidity',\n call: 'eth_compileSolidity',\n params: 1\n});\n\nvar compileLLL = new Method({\n name: 'compile.lll',\n call: 'eth_compileLLL',\n params: 1\n});\n\nvar compileSerpent = new Method({\n name: 'compile.serpent',\n call: 'eth_compileSerpent',\n params: 1\n});\n\nvar submitWork = new Method({\n name: 'submitWork',\n call: 'eth_submitWork',\n params: 3\n});\n\nvar getWork = new Method({\n name: 'getWork',\n call: 'eth_getWork',\n params: 0\n});\n\nvar methods = [\n getBalance,\n getStorageAt,\n getCode,\n getBlock,\n getUncle,\n getCompilers,\n getBlockTransactionCount,\n getBlockUncleCount,\n getTransaction,\n getTransactionFromBlock,\n getTransactionCount,\n call,\n estimateGas,\n sendRawTransaction,\n sendTransaction,\n compileSolidity,\n compileLLL,\n compileSerpent,\n submitWork,\n getWork\n];\n\n/// @returns an array of objects describing web3.eth api properties\n\n\n\nvar properties = [\n new Property({\n name: 'coinbase',\n getter: 'eth_coinbase'\n }),\n new Property({\n name: 'mining',\n getter: 'eth_mining'\n }),\n new Property({\n name: 'hashrate',\n getter: 'eth_hashrate',\n outputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'gasPrice',\n getter: 'eth_gasPrice',\n outputFormatter: formatters.outputBigNumberFormatter\n }),\n new Property({\n name: 'accounts',\n getter: 'eth_accounts'\n }),\n new Property({\n name: 'blockNumber',\n getter: 'eth_blockNumber',\n outputFormatter: utils.toDecimal\n })\n];\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file event.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar utils = require('../utils/utils');\nvar coder = require('../solidity/coder');\nvar formatters = require('./formatters');\nvar sha3 = require('../utils/sha3');\nvar Filter = require('./filter');\nvar watches = require('./watches');\n\n/**\n * This prototype should be used to create event filters\n */\nvar SolidityEvent = function (json, address) {\n this._params = json.inputs;\n this._name = utils.transformToFullName(json);\n this._address = address;\n this._anonymous = json.anonymous;\n};\n\n/**\n * Should be used to get filtered param types\n *\n * @method types\n * @param {Bool} decide if returned typed should be indexed\n * @return {Array} array of types\n */\nSolidityEvent.prototype.types = function (indexed) {\n return this._params.filter(function (i) {\n return i.indexed === indexed;\n }).map(function (i) {\n return i.type;\n });\n};\n\n/**\n * Should be used to get event display name\n *\n * @method displayName\n * @return {String} event display name\n */\nSolidityEvent.prototype.displayName = function () {\n return utils.extractDisplayName(this._name);\n};\n\n/**\n * Should be used to get event type name\n *\n * @method typeName\n * @return {String} event type name\n */\nSolidityEvent.prototype.typeName = function () {\n return utils.extractTypeName(this._name);\n};\n\n/**\n * Should be used to get event signature\n *\n * @method signature\n * @return {String} event signature\n */\nSolidityEvent.prototype.signature = function () {\n return sha3(this._name);\n};\n\n/**\n * Should be used to encode indexed params and options to one final object\n * \n * @method encode\n * @param {Object} indexed\n * @param {Object} options\n * @return {Object} everything combined together and encoded\n */\nSolidityEvent.prototype.encode = function (indexed, options) {\n indexed = indexed || {};\n options = options || {};\n var result = {};\n\n ['fromBlock', 'toBlock'].filter(function (f) {\n return options[f] !== undefined;\n }).forEach(function (f) {\n result[f] = formatters.inputBlockNumberFormatter(options[f]);\n });\n\n result.topics = [];\n\n if (!this._anonymous) {\n result.address = this._address;\n result.topics.push('0x' + this.signature());\n }\n\n var indexedTopics = this._params.filter(function (i) {\n return i.indexed === true;\n }).map(function (i) {\n var value = indexed[i.name];\n if (value === undefined || value === null) {\n return null;\n }\n \n if (utils.isArray(value)) {\n return value.map(function (v) {\n return '0x' + coder.encodeParam(i.type, v);\n });\n }\n return '0x' + coder.encodeParam(i.type, value);\n });\n\n result.topics = result.topics.concat(indexedTopics);\n\n return result;\n};\n\n/**\n * Should be used to decode indexed params and options\n *\n * @method decode\n * @param {Object} data\n * @return {Object} result object with decoded indexed && not indexed params\n */\nSolidityEvent.prototype.decode = function (data) {\n \n data.data = data.data || '';\n data.topics = data.topics || [];\n\n var argTopics = this._anonymous ? data.topics : data.topics.slice(1);\n var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(\"\");\n var indexedParams = coder.decodeParams(this.types(true), indexedData); \n\n var notIndexedData = data.data.slice(2);\n var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData);\n \n var result = formatters.outputLogFormatter(data);\n result.event = this.displayName();\n result.address = data.address;\n\n result.args = this._params.reduce(function (acc, current) {\n acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift();\n return acc;\n }, {});\n\n delete result.data;\n delete result.topics;\n\n return result;\n};\n\n/**\n * Should be used to create new filter object from event\n *\n * @method execute\n * @param {Object} indexed\n * @param {Object} options\n * @return {Object} filter object\n */\nSolidityEvent.prototype.execute = function (indexed, options, callback) {\n\n if (utils.isFunction(arguments[arguments.length - 1])) {\n callback = arguments[arguments.length - 1];\n if(arguments.length === 2)\n options = null;\n if(arguments.length === 1) {\n options = null;\n indexed = {};\n }\n }\n \n var o = this.encode(indexed, options);\n var formatter = this.decode.bind(this);\n return new Filter(o, watches.eth(), formatter, callback);\n};\n\n/**\n * Should be used to attach event to contract object\n *\n * @method attachToContract\n * @param {Contract}\n */\nSolidityEvent.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n var displayName = this.displayName();\n if (!contract[displayName]) {\n contract[displayName] = execute;\n }\n contract[displayName][this.typeName()] = this.execute.bind(this, contract);\n};\n\nmodule.exports = SolidityEvent;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar RequestManager = require('./requestmanager');\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\n\n/**\n* Converts a given topic to a hex string, but also allows null values.\n*\n* @param {Mixed} value\n* @return {String}\n*/\nvar toTopic = function(value){\n\n if(value === null || typeof value === 'undefined')\n return null;\n\n value = String(value);\n\n if(value.indexOf('0x') === 0)\n return value;\n else\n return utils.fromAscii(value);\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n\n if (utils.isString(options)) {\n return options;\n } \n\n options = options || {};\n\n // make sure topics, get converted to hex\n options.topics = options.topics || [];\n options.topics = options.topics.map(function(topic){\n return (utils.isArray(topic)) ? topic.map(toTopic) : toTopic(topic);\n });\n\n // lazy load\n return {\n topics: options.topics,\n to: options.to,\n address: options.address,\n fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),\n toBlock: formatters.inputBlockNumberFormatter(options.toBlock) \n }; \n};\n\n/**\nAdds the callback and sets up the methods, to iterate over the results.\n\n@method getLogsAtStart\n@param {Object} self\n@param {funciton} \n*/\nvar getLogsAtStart = function(self, callback){\n // call getFilterLogs for the first watch callback start\n if (!utils.isString(self.options)) {\n self.get(function (err, messages) {\n // don't send all the responses to all the watches again... just to self one\n if (err) {\n callback(err);\n }\n\n messages.forEach(function (message) {\n callback(null, message);\n });\n });\n }\n};\n\n/**\nAdds the callback and sets up the methods, to iterate over the results.\n\n@method pollFilter\n@param {Object} self\n*/\nvar pollFilter = function(self) {\n\n var onMessage = function (error, messages) {\n if (error) {\n return self.callbacks.forEach(function (callback) {\n callback(error);\n });\n }\n\n messages.forEach(function (message) {\n message = self.formatter ? self.formatter(message) : message;\n self.callbacks.forEach(function (callback) {\n callback(null, message);\n });\n });\n };\n\n RequestManager.getInstance().startPolling({\n method: self.implementation.poll.call,\n params: [self.filterId],\n }, self.filterId, onMessage, self.stopWatching.bind(self));\n\n};\n\nvar Filter = function (options, methods, formatter, callback) {\n var self = this;\n var implementation = {};\n methods.forEach(function (method) {\n method.attachToObject(implementation);\n });\n this.options = getOptions(options);\n this.implementation = implementation;\n this.filterId = null;\n this.callbacks = [];\n this.pollFilters = [];\n this.formatter = formatter;\n this.implementation.newFilter(this.options, function(error, id){\n if(error) {\n self.callbacks.forEach(function(cb){\n cb(error);\n });\n } else {\n self.filterId = id;\n\n // get filter logs for the already existing watch calls\n self.callbacks.forEach(function(cb){\n getLogsAtStart(self, cb);\n });\n if(self.callbacks.length > 0)\n pollFilter(self);\n\n // start to watch immediately\n if(callback) {\n return self.watch(callback);\n }\n }\n });\n\n};\n\nFilter.prototype.watch = function (callback) {\n this.callbacks.push(callback);\n\n if(this.filterId) {\n getLogsAtStart(this, callback);\n pollFilter(this);\n }\n\n return this;\n};\n\nFilter.prototype.stopWatching = function () {\n RequestManager.getInstance().stopPolling(this.filterId);\n // remove filter async\n this.implementation.uninstallFilter(this.filterId, function(){});\n this.callbacks = [];\n};\n\nFilter.prototype.get = function (callback) {\n var self = this;\n if (utils.isFunction(callback)) {\n this.implementation.getLogs(this.filterId, function(err, res){\n if (err) {\n callback(err);\n } else {\n callback(null, res.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n }));\n }\n });\n } else {\n var logs = this.implementation.getLogs(this.filterId);\n return logs.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n });\n }\n\n return this;\n};\n\nmodule.exports = Filter;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file formatters.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar config = require('../utils/config');\n\n/**\n * Should the format output to a big number\n *\n * @method outputBigNumberFormatter\n * @param {String|Number|BigNumber}\n * @returns {BigNumber} object\n */\nvar outputBigNumberFormatter = function (number) {\n return utils.toBigNumber(number);\n};\n\nvar isPredefinedBlockNumber = function (blockNumber) {\n return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest';\n};\n\nvar inputDefaultBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return config.defaultBlock;\n }\n return inputBlockNumberFormatter(blockNumber);\n};\n\nvar inputBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return undefined;\n } else if (isPredefinedBlockNumber(blockNumber)) {\n return blockNumber;\n }\n return utils.toHex(blockNumber);\n};\n\n/**\n * Formats the input of a transaction and converts all values to HEX\n *\n * @method inputTransactionFormatter\n * @param {Object} transaction options\n * @returns object\n*/\nvar inputTransactionFormatter = function (options){\n\n options.from = options.from || config.defaultAccount;\n\n // make code -> data\n if (options.code) {\n options.data = options.code;\n delete options.code;\n }\n\n ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {\n return options[key] !== undefined;\n }).forEach(function(key){\n options[key] = utils.fromDecimal(options[key]);\n });\n\n return options; \n};\n\n/**\n * Formats the output of a transaction to its proper values\n * \n * @method outputTransactionFormatter\n * @param {Object} transaction\n * @returns {Object} transaction\n*/\nvar outputTransactionFormatter = function (tx){\n if(tx.blockNumber !== null)\n tx.blockNumber = utils.toDecimal(tx.blockNumber);\n if(tx.transactionIndex !== null)\n tx.transactionIndex = utils.toDecimal(tx.transactionIndex);\n tx.nonce = utils.toDecimal(tx.nonce);\n tx.gas = utils.toDecimal(tx.gas);\n tx.gasPrice = utils.toBigNumber(tx.gasPrice);\n tx.value = utils.toBigNumber(tx.value);\n return tx;\n};\n\n/**\n * Formats the output of a block to its proper values\n *\n * @method outputBlockFormatter\n * @param {Object} block object \n * @returns {Object} block object\n*/\nvar outputBlockFormatter = function(block) {\n\n // transform to number\n block.gasLimit = utils.toDecimal(block.gasLimit);\n block.gasUsed = utils.toDecimal(block.gasUsed);\n block.size = utils.toDecimal(block.size);\n block.timestamp = utils.toDecimal(block.timestamp);\n if(block.number !== null)\n block.number = utils.toDecimal(block.number);\n\n block.difficulty = utils.toBigNumber(block.difficulty);\n block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);\n\n if (utils.isArray(block.transactions)) {\n block.transactions.forEach(function(item){\n if(!utils.isString(item))\n return outputTransactionFormatter(item);\n });\n }\n\n return block;\n};\n\n/**\n * Formats the output of a log\n * \n * @method outputLogFormatter\n * @param {Object} log object\n * @returns {Object} log\n*/\nvar outputLogFormatter = function(log) {\n if(log.blockNumber !== null)\n log.blockNumber = utils.toDecimal(log.blockNumber);\n if(log.transactionIndex !== null)\n log.transactionIndex = utils.toDecimal(log.transactionIndex);\n if(log.logIndex !== null)\n log.logIndex = utils.toDecimal(log.logIndex);\n\n return log;\n};\n\n/**\n * Formats the input of a whisper post and converts all values to HEX\n *\n * @method inputPostFormatter\n * @param {Object} transaction object\n * @returns {Object}\n*/\nvar inputPostFormatter = function(post) {\n\n post.payload = utils.toHex(post.payload);\n post.ttl = utils.fromDecimal(post.ttl);\n post.workToProve = utils.fromDecimal(post.workToProve);\n post.priority = utils.fromDecimal(post.priority);\n\n // fallback\n if (!utils.isArray(post.topics)) {\n post.topics = post.topics ? [post.topics] : [];\n }\n\n // format the following options\n post.topics = post.topics.map(function(topic){\n return utils.fromAscii(topic);\n });\n\n return post; \n};\n\n/**\n * Formats the output of a received post message\n *\n * @method outputPostFormatter\n * @param {Object}\n * @returns {Object}\n */\nvar outputPostFormatter = function(post){\n\n post.expiry = utils.toDecimal(post.expiry);\n post.sent = utils.toDecimal(post.sent);\n post.ttl = utils.toDecimal(post.ttl);\n post.workProved = utils.toDecimal(post.workProved);\n post.payloadRaw = post.payload;\n post.payload = utils.toAscii(post.payload);\n\n if (utils.isJson(post.payload)) {\n post.payload = JSON.parse(post.payload);\n }\n\n // format the following options\n if (!post.topics) {\n post.topics = [];\n }\n post.topics = post.topics.map(function(topic){\n return utils.toAscii(topic);\n });\n\n return post;\n};\n\nmodule.exports = {\n inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,\n inputBlockNumberFormatter: inputBlockNumberFormatter,\n inputTransactionFormatter: inputTransactionFormatter,\n inputPostFormatter: inputPostFormatter,\n outputBigNumberFormatter: outputBigNumberFormatter,\n outputTransactionFormatter: outputTransactionFormatter,\n outputBlockFormatter: outputBlockFormatter,\n outputLogFormatter: outputLogFormatter,\n outputPostFormatter: outputPostFormatter\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file errors.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nmodule.exports = {\n InvalidNumberOfParams: function () {\n return new Error('Invalid number of input parameters');\n },\n InvalidConnection: function (host){\n return new Error('CONNECTION ERROR: Couldn\\'t connect to node '+ host +', is it running?');\n },\n InvalidProvider: function () {\n return new Error('Providor not set or invalid');\n },\n InvalidResponse: function (result){\n var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: '+ result;\n return new Error(message);\n }\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file eth.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\n/**\n * Web3\n *\n * @module web3\n */\n\n/**\n * Eth methods and properties\n *\n * An example method object can look as follows:\n *\n * {\n * name: 'getBlock',\n * call: blockCall,\n * params: 2,\n * outputFormatter: formatters.outputBlockFormatter,\n * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter\n * utils.toHex, // formats paramter 1\n * function(param){ return !!param; } // formats paramter 2\n * ]\n * },\n *\n * @class [web3] eth\n * @constructor\n */\n\n\"use strict\";\n\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Method = require('./method');\nvar Property = require('./property');\n\nvar blockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? \"eth_getBlockByHash\" : \"eth_getBlockByNumber\";\n};\n\nvar transactionFromBlockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';\n};\n\nvar uncleCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';\n};\n\nvar getBlockTransactionCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';\n};\n\nvar uncleCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';\n};\n\n/// @returns an array of objects describing web3.eth api methods\n\nvar getBalance = new Method({\n name: 'getBalance',\n call: 'eth_getBalance',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: formatters.outputBigNumberFormatter\n});\n\nvar getStorageAt = new Method({\n name: 'getStorageAt',\n call: 'eth_getStorageAt',\n params: 3,\n inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getCode = new Method({\n name: 'getCode',\n call: 'eth_getCode',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getBlock = new Method({\n name: 'getBlock',\n call: blockCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter\n});\n\nvar getUncle = new Method({\n name: 'getUncle',\n call: uncleCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],\n outputFormatter: formatters.outputBlockFormatter,\n\n});\n\nvar getCompilers = new Method({\n name: 'getCompilers',\n call: 'eth_getCompilers',\n params: 0\n});\n\nvar getBlockTransactionCount = new Method({\n name: 'getBlockTransactionCount',\n call: getBlockTransactionCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getBlockUncleCount = new Method({\n name: 'getBlockUncleCount',\n call: uncleCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getTransaction = new Method({\n name: 'getTransaction',\n call: 'eth_getTransactionByHash',\n params: 1,\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionFromBlock = new Method({\n name: 'getTransactionFromBlock',\n call: transactionFromBlockCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionReceipt = new Method({\n name: 'getTransactionReceipt',\n call: 'eth_getTransactionReceipt',\n params: 1,\n outputFormatter: formatters.outputTransactionReceiptFormatter\n});\n\nvar getTransactionCount = new Method({\n name: 'getTransactionCount',\n call: 'eth_getTransactionCount',\n params: 2,\n inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar sendRawTransaction = new Method({\n name: 'sendRawTransaction',\n call: 'eth_sendRawTransaction',\n params: 1,\n inputFormatter: [null]\n});\n\nvar sendTransaction = new Method({\n name: 'sendTransaction',\n call: 'eth_sendTransaction',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter]\n});\n\nvar call = new Method({\n name: 'call',\n call: 'eth_call',\n params: 2,\n inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar estimateGas = new Method({\n name: 'estimateGas',\n call: 'eth_estimateGas',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar compileSolidity = new Method({\n name: 'compile.solidity',\n call: 'eth_compileSolidity',\n params: 1\n});\n\nvar compileLLL = new Method({\n name: 'compile.lll',\n call: 'eth_compileLLL',\n params: 1\n});\n\nvar compileSerpent = new Method({\n name: 'compile.serpent',\n call: 'eth_compileSerpent',\n params: 1\n});\n\nvar submitWork = new Method({\n name: 'submitWork',\n call: 'eth_submitWork',\n params: 3\n});\n\nvar getWork = new Method({\n name: 'getWork',\n call: 'eth_getWork',\n params: 0\n});\n\nvar methods = [\n getBalance,\n getStorageAt,\n getCode,\n getBlock,\n getUncle,\n getCompilers,\n getBlockTransactionCount,\n getBlockUncleCount,\n getTransaction,\n getTransactionFromBlock,\n getTransactionReceipt,\n getTransactionCount,\n call,\n estimateGas,\n sendRawTransaction,\n sendTransaction,\n compileSolidity,\n compileLLL,\n compileSerpent,\n submitWork,\n getWork\n];\n\n/// @returns an array of objects describing web3.eth api properties\n\n\n\nvar properties = [\n new Property({\n name: 'coinbase',\n getter: 'eth_coinbase'\n }),\n new Property({\n name: 'mining',\n getter: 'eth_mining'\n }),\n new Property({\n name: 'hashrate',\n getter: 'eth_hashrate',\n outputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'gasPrice',\n getter: 'eth_gasPrice',\n outputFormatter: formatters.outputBigNumberFormatter\n }),\n new Property({\n name: 'accounts',\n getter: 'eth_accounts'\n }),\n new Property({\n name: 'blockNumber',\n getter: 'eth_blockNumber',\n outputFormatter: utils.toDecimal\n })\n];\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file event.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar utils = require('../utils/utils');\nvar coder = require('../solidity/coder');\nvar formatters = require('./formatters');\nvar sha3 = require('../utils/sha3');\nvar Filter = require('./filter');\nvar watches = require('./watches');\n\n/**\n * This prototype should be used to create event filters\n */\nvar SolidityEvent = function (json, address) {\n this._params = json.inputs;\n this._name = utils.transformToFullName(json);\n this._address = address;\n this._anonymous = json.anonymous;\n};\n\n/**\n * Should be used to get filtered param types\n *\n * @method types\n * @param {Bool} decide if returned typed should be indexed\n * @return {Array} array of types\n */\nSolidityEvent.prototype.types = function (indexed) {\n return this._params.filter(function (i) {\n return i.indexed === indexed;\n }).map(function (i) {\n return i.type;\n });\n};\n\n/**\n * Should be used to get event display name\n *\n * @method displayName\n * @return {String} event display name\n */\nSolidityEvent.prototype.displayName = function () {\n return utils.extractDisplayName(this._name);\n};\n\n/**\n * Should be used to get event type name\n *\n * @method typeName\n * @return {String} event type name\n */\nSolidityEvent.prototype.typeName = function () {\n return utils.extractTypeName(this._name);\n};\n\n/**\n * Should be used to get event signature\n *\n * @method signature\n * @return {String} event signature\n */\nSolidityEvent.prototype.signature = function () {\n return sha3(this._name);\n};\n\n/**\n * Should be used to encode indexed params and options to one final object\n * \n * @method encode\n * @param {Object} indexed\n * @param {Object} options\n * @return {Object} everything combined together and encoded\n */\nSolidityEvent.prototype.encode = function (indexed, options) {\n indexed = indexed || {};\n options = options || {};\n var result = {};\n\n ['fromBlock', 'toBlock'].filter(function (f) {\n return options[f] !== undefined;\n }).forEach(function (f) {\n result[f] = formatters.inputBlockNumberFormatter(options[f]);\n });\n\n result.topics = [];\n\n result.address = this._address;\n if (!this._anonymous) {\n result.topics.push('0x' + this.signature());\n }\n\n var indexedTopics = this._params.filter(function (i) {\n return i.indexed === true;\n }).map(function (i) {\n var value = indexed[i.name];\n if (value === undefined || value === null) {\n return null;\n }\n \n if (utils.isArray(value)) {\n return value.map(function (v) {\n return '0x' + coder.encodeParam(i.type, v);\n });\n }\n return '0x' + coder.encodeParam(i.type, value);\n });\n\n result.topics = result.topics.concat(indexedTopics);\n\n return result;\n};\n\n/**\n * Should be used to decode indexed params and options\n *\n * @method decode\n * @param {Object} data\n * @return {Object} result object with decoded indexed && not indexed params\n */\nSolidityEvent.prototype.decode = function (data) {\n \n data.data = data.data || '';\n data.topics = data.topics || [];\n\n var argTopics = this._anonymous ? data.topics : data.topics.slice(1);\n var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(\"\");\n var indexedParams = coder.decodeParams(this.types(true), indexedData); \n\n var notIndexedData = data.data.slice(2);\n var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData);\n \n var result = formatters.outputLogFormatter(data);\n result.event = this.displayName();\n result.address = data.address;\n\n result.args = this._params.reduce(function (acc, current) {\n acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift();\n return acc;\n }, {});\n\n delete result.data;\n delete result.topics;\n\n return result;\n};\n\n/**\n * Should be used to create new filter object from event\n *\n * @method execute\n * @param {Object} indexed\n * @param {Object} options\n * @return {Object} filter object\n */\nSolidityEvent.prototype.execute = function (indexed, options, callback) {\n\n if (utils.isFunction(arguments[arguments.length - 1])) {\n callback = arguments[arguments.length - 1];\n if(arguments.length === 2)\n options = null;\n if(arguments.length === 1) {\n options = null;\n indexed = {};\n }\n }\n \n var o = this.encode(indexed, options);\n var formatter = this.decode.bind(this);\n return new Filter(o, watches.eth(), formatter, callback);\n};\n\n/**\n * Should be used to attach event to contract object\n *\n * @method attachToContract\n * @param {Contract}\n */\nSolidityEvent.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n var displayName = this.displayName();\n if (!contract[displayName]) {\n contract[displayName] = execute;\n }\n contract[displayName][this.typeName()] = this.execute.bind(this, contract);\n};\n\nmodule.exports = SolidityEvent;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar RequestManager = require('./requestmanager');\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\n\n/**\n* Converts a given topic to a hex string, but also allows null values.\n*\n* @param {Mixed} value\n* @return {String}\n*/\nvar toTopic = function(value){\n\n if(value === null || typeof value === 'undefined')\n return null;\n\n value = String(value);\n\n if(value.indexOf('0x') === 0)\n return value;\n else\n return utils.fromAscii(value);\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n\n if (utils.isString(options)) {\n return options;\n } \n\n options = options || {};\n\n // make sure topics, get converted to hex\n options.topics = options.topics || [];\n options.topics = options.topics.map(function(topic){\n return (utils.isArray(topic)) ? topic.map(toTopic) : toTopic(topic);\n });\n\n // lazy load\n return {\n topics: options.topics,\n to: options.to,\n address: options.address,\n fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),\n toBlock: formatters.inputBlockNumberFormatter(options.toBlock) \n }; \n};\n\n/**\nAdds the callback and sets up the methods, to iterate over the results.\n\n@method getLogsAtStart\n@param {Object} self\n@param {funciton} \n*/\nvar getLogsAtStart = function(self, callback){\n // call getFilterLogs for the first watch callback start\n if (!utils.isString(self.options)) {\n self.get(function (err, messages) {\n // don't send all the responses to all the watches again... just to self one\n if (err) {\n callback(err);\n }\n\n if(utils.isArray(messages)) {\n messages.forEach(function (message) {\n callback(null, message);\n });\n }\n });\n }\n};\n\n/**\nAdds the callback and sets up the methods, to iterate over the results.\n\n@method pollFilter\n@param {Object} self\n*/\nvar pollFilter = function(self) {\n\n var onMessage = function (error, messages) {\n if (error) {\n return self.callbacks.forEach(function (callback) {\n callback(error);\n });\n }\n\n messages.forEach(function (message) {\n message = self.formatter ? self.formatter(message) : message;\n self.callbacks.forEach(function (callback) {\n callback(null, message);\n });\n });\n };\n\n RequestManager.getInstance().startPolling({\n method: self.implementation.poll.call,\n params: [self.filterId],\n }, self.filterId, onMessage, self.stopWatching.bind(self));\n\n};\n\nvar Filter = function (options, methods, formatter, callback) {\n var self = this;\n var implementation = {};\n methods.forEach(function (method) {\n method.attachToObject(implementation);\n });\n this.options = getOptions(options);\n this.implementation = implementation;\n this.filterId = null;\n this.callbacks = [];\n this.pollFilters = [];\n this.formatter = formatter;\n this.implementation.newFilter(this.options, function(error, id){\n if(error) {\n self.callbacks.forEach(function(cb){\n cb(error);\n });\n } else {\n self.filterId = id;\n\n // get filter logs for the already existing watch calls\n self.callbacks.forEach(function(cb){\n getLogsAtStart(self, cb);\n });\n if(self.callbacks.length > 0)\n pollFilter(self);\n\n // start to watch immediately\n if(callback) {\n return self.watch(callback);\n }\n }\n });\n\n};\n\nFilter.prototype.watch = function (callback) {\n this.callbacks.push(callback);\n\n if(this.filterId) {\n getLogsAtStart(this, callback);\n pollFilter(this);\n }\n\n return this;\n};\n\nFilter.prototype.stopWatching = function () {\n RequestManager.getInstance().stopPolling(this.filterId);\n // remove filter async\n this.implementation.uninstallFilter(this.filterId, function(){});\n this.callbacks = [];\n};\n\nFilter.prototype.get = function (callback) {\n var self = this;\n if (utils.isFunction(callback)) {\n this.implementation.getLogs(this.filterId, function(err, res){\n if (err) {\n callback(err);\n } else {\n callback(null, res.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n }));\n }\n });\n } else {\n var logs = this.implementation.getLogs(this.filterId);\n return logs.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n });\n }\n\n return this;\n};\n\nmodule.exports = Filter;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file formatters.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar config = require('../utils/config');\n\n/**\n * Should the format output to a big number\n *\n * @method outputBigNumberFormatter\n * @param {String|Number|BigNumber}\n * @returns {BigNumber} object\n */\nvar outputBigNumberFormatter = function (number) {\n return utils.toBigNumber(number);\n};\n\nvar isPredefinedBlockNumber = function (blockNumber) {\n return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest';\n};\n\nvar inputDefaultBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return config.defaultBlock;\n }\n return inputBlockNumberFormatter(blockNumber);\n};\n\nvar inputBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return undefined;\n } else if (isPredefinedBlockNumber(blockNumber)) {\n return blockNumber;\n }\n return utils.toHex(blockNumber);\n};\n\n/**\n * Formats the input of a transaction and converts all values to HEX\n *\n * @method inputTransactionFormatter\n * @param {Object} transaction options\n * @returns object\n*/\nvar inputTransactionFormatter = function (options){\n\n options.from = options.from || config.defaultAccount;\n\n // make code -> data\n if (options.code) {\n options.data = options.code;\n delete options.code;\n }\n\n ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {\n return options[key] !== undefined;\n }).forEach(function(key){\n options[key] = utils.fromDecimal(options[key]);\n });\n\n return options; \n};\n\n/**\n * Formats the output of a transaction to its proper values\n * \n * @method outputTransactionFormatter\n * @param {Object} tx\n * @returns {Object}\n*/\nvar outputTransactionFormatter = function (tx){\n if(tx.blockNumber !== null)\n tx.blockNumber = utils.toDecimal(tx.blockNumber);\n if(tx.transactionIndex !== null)\n tx.transactionIndex = utils.toDecimal(tx.transactionIndex);\n tx.nonce = utils.toDecimal(tx.nonce);\n tx.gas = utils.toDecimal(tx.gas);\n tx.gasPrice = utils.toBigNumber(tx.gasPrice);\n tx.value = utils.toBigNumber(tx.value);\n return tx;\n};\n\n/**\n * Formats the output of a transaction receipt to its proper values\n * \n * @method outputTransactionReceiptFormatter\n * @param {Object} receipt\n * @returns {Object}\n*/\nvar outputTransactionReceiptFormatter = function (receipt){\n if(receipt.blockNumber !== null)\n receipt.blockNumber = utils.toDecimal(receipt.blockNumber);\n if(receipt.transactionIndex !== null)\n receipt.transactionIndex = utils.toDecimal(receipt.transactionIndex);\n receipt.cumulativeGasUsed = utils.toDecimal(receipt.cumulativeGasUsed);\n receipt.gasUsed = utils.toDecimal(receipt.gasUsed);\n\n if(utils.isArray(receipt.logs)) {\n receipt.logs = receipt.logs.map(function(log){\n return outputLogFormatter(log);\n });\n }\n\n return receipt;\n};\n\n/**\n * Formats the output of a block to its proper values\n *\n * @method outputBlockFormatter\n * @param {Object} block \n * @returns {Object}\n*/\nvar outputBlockFormatter = function(block) {\n\n // transform to number\n block.gasLimit = utils.toDecimal(block.gasLimit);\n block.gasUsed = utils.toDecimal(block.gasUsed);\n block.size = utils.toDecimal(block.size);\n block.timestamp = utils.toDecimal(block.timestamp);\n if(block.number !== null)\n block.number = utils.toDecimal(block.number);\n\n block.difficulty = utils.toBigNumber(block.difficulty);\n block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);\n\n if (utils.isArray(block.transactions)) {\n block.transactions.forEach(function(item){\n if(!utils.isString(item))\n return outputTransactionFormatter(item);\n });\n }\n\n return block;\n};\n\n/**\n * Formats the output of a log\n * \n * @method outputLogFormatter\n * @param {Object} log object\n * @returns {Object} log\n*/\nvar outputLogFormatter = function(log) {\n if(log.blockNumber !== null)\n log.blockNumber = utils.toDecimal(log.blockNumber);\n if(log.transactionIndex !== null)\n log.transactionIndex = utils.toDecimal(log.transactionIndex);\n if(log.logIndex !== null)\n log.logIndex = utils.toDecimal(log.logIndex);\n\n return log;\n};\n\n/**\n * Formats the input of a whisper post and converts all values to HEX\n *\n * @method inputPostFormatter\n * @param {Object} transaction object\n * @returns {Object}\n*/\nvar inputPostFormatter = function(post) {\n\n post.payload = utils.toHex(post.payload);\n post.ttl = utils.fromDecimal(post.ttl);\n post.workToProve = utils.fromDecimal(post.workToProve);\n post.priority = utils.fromDecimal(post.priority);\n\n // fallback\n if (!utils.isArray(post.topics)) {\n post.topics = post.topics ? [post.topics] : [];\n }\n\n // format the following options\n post.topics = post.topics.map(function(topic){\n return utils.fromAscii(topic);\n });\n\n return post; \n};\n\n/**\n * Formats the output of a received post message\n *\n * @method outputPostFormatter\n * @param {Object}\n * @returns {Object}\n */\nvar outputPostFormatter = function(post){\n\n post.expiry = utils.toDecimal(post.expiry);\n post.sent = utils.toDecimal(post.sent);\n post.ttl = utils.toDecimal(post.ttl);\n post.workProved = utils.toDecimal(post.workProved);\n post.payloadRaw = post.payload;\n post.payload = utils.toAscii(post.payload);\n\n if (utils.isJson(post.payload)) {\n post.payload = JSON.parse(post.payload);\n }\n\n // format the following options\n if (!post.topics) {\n post.topics = [];\n }\n post.topics = post.topics.map(function(topic){\n return utils.toAscii(topic);\n });\n\n return post;\n};\n\nmodule.exports = {\n inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,\n inputBlockNumberFormatter: inputBlockNumberFormatter,\n inputTransactionFormatter: inputTransactionFormatter,\n inputPostFormatter: inputPostFormatter,\n outputBigNumberFormatter: outputBigNumberFormatter,\n outputTransactionFormatter: outputTransactionFormatter,\n outputTransactionReceiptFormatter: outputTransactionReceiptFormatter,\n outputBlockFormatter: outputBlockFormatter,\n outputLogFormatter: outputLogFormatter,\n outputPostFormatter: outputPostFormatter\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file function.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar web3 = require('../web3');\nvar coder = require('../solidity/coder');\nvar utils = require('../utils/utils');\nvar formatters = require('./formatters');\nvar sha3 = require('../utils/sha3');\n\n/**\n * This prototype should be used to call/sendTransaction to solidity functions\n */\nvar SolidityFunction = function (json, address) {\n this._inputTypes = json.inputs.map(function (i) {\n return i.type;\n });\n this._outputTypes = json.outputs.map(function (i) {\n return i.type;\n });\n this._constant = json.constant;\n this._name = utils.transformToFullName(json);\n this._address = address;\n};\n\nSolidityFunction.prototype.extractCallback = function (args) {\n if (utils.isFunction(args[args.length - 1])) {\n return args.pop(); // modify the args array!\n }\n};\n\nSolidityFunction.prototype.extractDefaultBlock = function (args) {\n if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) {\n return formatters.inputDefaultBlockNumberFormatter(args.pop()); // modify the args array!\n }\n};\n\n/**\n * Should be used to create payload from arguments\n *\n * @method toPayload\n * @param {Array} solidity function params\n * @param {Object} optional payload options\n */\nSolidityFunction.prototype.toPayload = function (args) {\n var options = {};\n if (args.length > this._inputTypes.length && utils.isObject(args[args.length -1])) {\n options = args[args.length - 1];\n }\n options.to = this._address;\n options.data = '0x' + this.signature() + coder.encodeParams(this._inputTypes, args);\n return options;\n};\n\n/**\n * Should be used to get function signature\n *\n * @method signature\n * @return {String} function signature\n */\nSolidityFunction.prototype.signature = function () {\n return sha3(this._name).slice(0, 8);\n};\n\n\nSolidityFunction.prototype.unpackOutput = function (output) {\n if (!output) {\n return;\n }\n\n output = output.length >= 2 ? output.slice(2) : output;\n var result = coder.decodeParams(this._outputTypes, output);\n return result.length === 1 ? result[0] : result;\n};\n\n/**\n * Calls a contract function.\n *\n * @method call\n * @param {...Object} Contract function arguments\n * @param {function} If the last argument is a function, the contract function\n * call will be asynchronous, and the callback will be passed the\n * error and result.\n * @return {String} output bytes\n */\nSolidityFunction.prototype.call = function () {\n var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; });\n var callback = this.extractCallback(args);\n var defaultBlock = this.extractDefaultBlock(args);\n var payload = this.toPayload(args);\n\n\n if (!callback) {\n var output = web3.eth.call(payload, defaultBlock);\n return this.unpackOutput(output);\n } \n \n var self = this;\n web3.eth.call(payload, defaultBlock, function (error, output) {\n callback(error, self.unpackOutput(output));\n });\n};\n\n/**\n * Should be used to sendTransaction to solidity function\n *\n * @method sendTransaction\n * @param {Object} options\n */\nSolidityFunction.prototype.sendTransaction = function () {\n var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; });\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n\n if (!callback) {\n return web3.eth.sendTransaction(payload);\n }\n\n web3.eth.sendTransaction(payload, callback);\n};\n\n/**\n * Should be used to estimateGas of solidity function\n *\n * @method estimateGas\n * @param {Object} options\n */\nSolidityFunction.prototype.estimateGas = function () {\n var args = Array.prototype.slice.call(arguments);\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n\n if (!callback) {\n return web3.eth.estimateGas(payload);\n }\n\n web3.eth.estimateGas(payload, callback);\n};\n\n/**\n * Should be used to get function display name\n *\n * @method displayName\n * @return {String} display name of the function\n */\nSolidityFunction.prototype.displayName = function () {\n return utils.extractDisplayName(this._name);\n};\n\n/**\n * Should be used to get function type name\n *\n * @method typeName\n * @return {String} type name of the function\n */\nSolidityFunction.prototype.typeName = function () {\n return utils.extractTypeName(this._name);\n};\n\n/**\n * Should be called to get rpc requests from solidity function\n *\n * @method request\n * @returns {Object}\n */\nSolidityFunction.prototype.request = function () {\n var args = Array.prototype.slice.call(arguments);\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n var format = this.unpackOutput.bind(this);\n \n return {\n method: this._constant ? 'eth_call' : 'eth_sendTransaction',\n callback: callback,\n params: [payload], \n format: format\n };\n};\n\n/**\n * Should be called to execute function\n *\n * @method execute\n */\nSolidityFunction.prototype.execute = function () {\n var transaction = !this._constant;\n\n // send transaction\n if (transaction) {\n return this.sendTransaction.apply(this, Array.prototype.slice.call(arguments));\n }\n\n // call\n return this.call.apply(this, Array.prototype.slice.call(arguments));\n};\n\n/**\n * Should be called to attach function to contract\n *\n * @method attachToContract\n * @param {Contract}\n */\nSolidityFunction.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n execute.request = this.request.bind(this);\n execute.call = this.call.bind(this);\n execute.sendTransaction = this.sendTransaction.bind(this);\n execute.estimateGas = this.estimateGas.bind(this);\n var displayName = this.displayName();\n if (!contract[displayName]) {\n contract[displayName] = execute;\n }\n contract[displayName][this.typeName()] = execute; // circular!!!!\n};\n\nmodule.exports = SolidityFunction;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpprovider.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * @date 2014\n */\n\n\"use strict\";\n\n// resolves the problem for electron/atom shell environments, which use node integration, but have no process variable available\nvar XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\nvar errors = require('./errors');\n\nvar HttpProvider = function (host) {\n this.host = host || 'http://localhost:8545';\n};\n\nHttpProvider.prototype.send = function (payload) {\n var request = new XMLHttpRequest();\n\n request.open('POST', this.host, false);\n request.setRequestHeader('Content-type','application/json');\n \n try {\n request.send(JSON.stringify(payload));\n } catch(error) {\n throw errors.InvalidConnection(this.host);\n }\n\n\n // check request.status\n // TODO: throw an error here! it cannot silently fail!!!\n //if (request.status !== 200) {\n //return;\n //}\n\n var result = request.responseText;\n\n try {\n result = JSON.parse(result);\n } catch(e) {\n throw errors.InvalidResponse(result); \n }\n\n return result;\n};\n\nHttpProvider.prototype.sendAsync = function (payload, callback) {\n var request = new XMLHttpRequest();\n request.onreadystatechange = function() {\n if (request.readyState === 4) {\n var result = request.responseText;\n var error = null;\n\n try {\n result = JSON.parse(result);\n } catch(e) {\n error = errors.InvalidResponse(result); \n }\n\n callback(error, result);\n }\n };\n\n request.open('POST', this.host, true);\n request.setRequestHeader('Content-type','application/json');\n \n try {\n request.send(JSON.stringify(payload));\n } catch(error) {\n callback(errors.InvalidConnection(this.host));\n }\n};\n\nmodule.exports = HttpProvider;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpprovider.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * @date 2015\n */\n\n\"use strict\";\n\nvar XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\nvar errors = require('./errors');\n\nvar HttpProvider = function (host) {\n this.host = host || 'http://localhost:8545';\n};\n\nHttpProvider.prototype.isConnected = function() {\n var request = new XMLHttpRequest();\n\n request.open('POST', this.host, false);\n request.setRequestHeader('Content-type','application/json');\n \n try {\n request.send(JSON.stringify({\n id: 9999999999,\n jsonrpc: '2.0',\n method: 'net_listening',\n params: []\n }));\n return true;\n } catch(e) {\n return false;\n }\n};\n\nHttpProvider.prototype.send = function (payload) {\n var request = new XMLHttpRequest();\n\n request.open('POST', this.host, false);\n request.setRequestHeader('Content-type','application/json');\n \n try {\n request.send(JSON.stringify(payload));\n } catch(error) {\n throw errors.InvalidConnection(this.host);\n }\n\n\n // check request.status\n // TODO: throw an error here! it cannot silently fail!!!\n //if (request.status !== 200) {\n //return;\n //}\n\n var result = request.responseText;\n\n try {\n result = JSON.parse(result);\n } catch(e) {\n throw errors.InvalidResponse(request.responseText); \n }\n\n return result;\n};\n\nHttpProvider.prototype.sendAsync = function (payload, callback) {\n var request = new XMLHttpRequest();\n request.onreadystatechange = function() {\n if (request.readyState === 4) {\n var result = request.responseText;\n var error = null;\n\n try {\n result = JSON.parse(result);\n } catch(e) {\n error = errors.InvalidResponse(request.responseText); \n }\n\n callback(error, result);\n }\n };\n\n request.open('POST', this.host, true);\n request.setRequestHeader('Content-type','application/json');\n \n try {\n request.send(JSON.stringify(payload));\n } catch(error) {\n callback(errors.InvalidConnection(this.host));\n }\n};\n\nmodule.exports = HttpProvider;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file icap.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\n\n/**\n * This prototype should be used to extract necessary information from iban address\n *\n * @param {String} iban\n */\nvar ICAP = function (iban) {\n this._iban = iban;\n};\n\n/**\n * Should be called to check if icap is correct\n *\n * @method isValid\n * @returns {Boolean} true if it is, otherwise false\n */\nICAP.prototype.isValid = function () {\n return utils.isIBAN(this._iban);\n};\n\n/**\n * Should be called to check if iban number is direct\n *\n * @method isDirect\n * @returns {Boolean} true if it is, otherwise false\n */\nICAP.prototype.isDirect = function () {\n return this._iban.length === 34;\n};\n\n/**\n * Should be called to check if iban number if indirect\n *\n * @method isIndirect\n * @returns {Boolean} true if it is, otherwise false\n */\nICAP.prototype.isIndirect = function () {\n return this._iban.length === 20;\n};\n\n/**\n * Should be called to get iban checksum\n * Uses the mod-97-10 checksumming protocol (ISO/IEC 7064:2003)\n *\n * @method checksum\n * @returns {String} checksum\n */\nICAP.prototype.checksum = function () {\n return this._iban.substr(2, 2);\n};\n\n/**\n * Should be called to get institution identifier\n * eg. XREG\n *\n * @method institution\n * @returns {String} institution identifier\n */\nICAP.prototype.institution = function () {\n return this.isIndirect() ? this._iban.substr(7, 4) : '';\n};\n\n/**\n * Should be called to get client identifier within institution\n * eg. GAVOFYORK\n *\n * @method client\n * @returns {String} client identifier\n */\nICAP.prototype.client = function () {\n return this.isIndirect() ? this._iban.substr(11) : '';\n};\n\n/**\n * Should be called to get client direct address\n *\n * @method address\n * @returns {String} client direct address\n */\nICAP.prototype.address = function () {\n return this.isDirect() ? this._iban.substr(4) : '';\n};\n\nmodule.exports = ICAP;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file ipcprovider.js\n * @authors:\n * Fabian Vogelsteller \n * @date 2015\n */\n\n\"use strict\";\n\nvar utils = require('../utils/utils');\nvar errors = require('./errors');\n\nvar errorTimeout = '{\"jsonrpc\": \"2.0\", \"error\": {\"code\": -32603, \"message\": \"IPC Request timed out for method \\'__method__\\'\"}, \"id\": \"__id__\"}';\n\n\nvar IpcProvider = function (path, net) {\n var _this = this;\n this.responseCallbacks = {};\n this.path = path;\n \n net = net || require('net');\n\n this.connection = net.connect({path: this.path});\n\n this.connection.on('error', function(e){\n console.error('IPC Connection Error', e);\n _this._timeout();\n });\n\n this.connection.on('end', function(){\n _this._timeout();\n }); \n\n\n // LISTEN FOR CONNECTION RESPONSES\n this.connection.on('data', function(data) {\n /*jshint maxcomplexity: 6 */\n\n _this._parseResponse(data.toString()).forEach(function(result){\n\n var id = null;\n\n // get the id which matches the returned id\n if(utils.isArray(result)) {\n result.forEach(function(load){\n if(_this.responseCallbacks[load.id])\n id = load.id;\n });\n } else {\n id = result.id;\n }\n\n // fire the callback\n if(_this.responseCallbacks[id]) {\n _this.responseCallbacks[id](null, result);\n delete _this.responseCallbacks[id];\n }\n });\n });\n};\n\n/**\nWill parse the response and make an array out of it.\n\n@method _parseResponse\n@param {String} data\n*/\nIpcProvider.prototype._parseResponse = function(data) {\n var _this = this,\n returnValues = [];\n \n // DE-CHUNKER\n var dechunkedData = data\n .replace(/\\}\\{/g,'}|--|{') // }{\n .replace(/\\}\\]\\[\\{/g,'}]|--|[{') // }][{\n .replace(/\\}\\[\\{/g,'}|--|[{') // }[{\n .replace(/\\}\\]\\{/g,'}]|--|{') // }]{\n .split('|--|');\n\n dechunkedData.forEach(function(data){\n\n // prepend the last chunk\n if(_this.lastChunk)\n data = _this.lastChunk + data;\n\n var result = null;\n\n try {\n result = JSON.parse(data);\n\n } catch(e) {\n\n _this.lastChunk = data;\n\n // start timeout to cancel all requests\n clearTimeout(_this.lastChunkTimeout);\n _this.lastChunkTimeout = setTimeout(function(){\n _this.timeout();\n throw errors.InvalidResponse(data);\n }, 1000 * 15);\n\n return;\n }\n\n // cancel timeout and set chunk to null\n clearTimeout(_this.lastChunkTimeout);\n _this.lastChunk = null;\n\n if(result)\n returnValues.push(result);\n });\n\n return returnValues;\n};\n\n\n/**\nGet the adds a callback to the responseCallbacks object,\nwhich will be called if a response matching the response Id will arrive.\n\n@method _addResponseCallback\n*/\nIpcProvider.prototype._addResponseCallback = function(payload, callback) {\n var id = payload.id || payload[0].id;\n var method = payload.method || payload[0].method;\n\n this.responseCallbacks[id] = callback;\n this.responseCallbacks[id].method = method;\n};\n\n/**\nTimeout all requests when the end/error event is fired\n\n@method _timeout\n*/\nIpcProvider.prototype._timeout = function() {\n for(var key in this.responseCallbacks) {\n if(this.responseCallbacks.hasOwnProperty(key)){\n this.responseCallbacks[key](errorTimeout.replace('__id__', key).replace('__method__', this.responseCallbacks[key].method));\n delete this.responseCallbacks[key];\n }\n }\n};\n\n\n/**\nCheck if the current connection is still valid.\n\n@method isConnected\n*/\nIpcProvider.prototype.isConnected = function() {\n var _this = this;\n\n // try reconnect, when connection is gone\n if(!_this.connection.writable)\n _this.connection.connect({path: _this.path});\n\n return !!this.connection.writable;\n};\n\nIpcProvider.prototype.send = function (payload) {\n\n if(this.connection.writeSync) {\n var result;\n\n // try reconnect, when connection is gone\n if(!this.connection.writable)\n this.connection.connect({path: this.path});\n\n var data = this.connection.writeSync(JSON.stringify(payload));\n\n try {\n result = JSON.parse(data);\n } catch(e) {\n throw errors.InvalidResponse(data); \n }\n\n return result;\n\n } else {\n throw new Error('You tried to send \"'+ payload.method +'\" synchronously. Synchronous requests are not supported by the IPC provider.');\n }\n};\n\nIpcProvider.prototype.sendAsync = function (payload, callback) {\n // try reconnect, when connection is gone\n if(!this.connection.writable)\n this.connection.connect({path: this.path});\n\n\n this.connection.write(JSON.stringify(payload));\n this._addResponseCallback(payload, callback);\n};\n\nmodule.exports = IpcProvider;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file jsonrpc.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Jsonrpc = function () {\n // singleton pattern\n if (arguments.callee._singletonInstance) {\n return arguments.callee._singletonInstance;\n }\n arguments.callee._singletonInstance = this;\n\n this.messageId = 1;\n};\n\n/**\n * @return {Jsonrpc} singleton\n */\nJsonrpc.getInstance = function () {\n var instance = new Jsonrpc();\n return instance;\n};\n\n/**\n * Should be called to valid json create payload object\n *\n * @method toPayload\n * @param {Function} method of jsonrpc call, required\n * @param {Array} params, an array of method params, optional\n * @returns {Object} valid jsonrpc payload object\n */\nJsonrpc.prototype.toPayload = function (method, params) {\n if (!method)\n console.error('jsonrpc method should be specified!');\n\n return {\n jsonrpc: '2.0',\n method: method,\n params: params || [],\n id: this.messageId++\n };\n};\n\n/**\n * Should be called to check if jsonrpc response is valid\n *\n * @method isValidResponse\n * @param {Object}\n * @returns {Boolean} true if response is valid, otherwise false\n */\nJsonrpc.prototype.isValidResponse = function (response) {\n return !!response &&\n !response.error &&\n response.jsonrpc === '2.0' &&\n typeof response.id === 'number' &&\n response.result !== undefined; // only undefined is not valid json object\n};\n\n/**\n * Should be called to create batch payload object\n *\n * @method toBatchPayload\n * @param {Array} messages, an array of objects with method (required) and params (optional) fields\n * @returns {Array} batch payload\n */\nJsonrpc.prototype.toBatchPayload = function (messages) {\n var self = this;\n return messages.map(function (message) {\n return self.toPayload(message.method, message.params);\n });\n};\n\nmodule.exports = Jsonrpc;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file method.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\nvar utils = require('../utils/utils');\nvar errors = require('./errors');\n\nvar Method = function (options) {\n this.name = options.name;\n this.call = options.call;\n this.params = options.params || 0;\n this.inputFormatter = options.inputFormatter;\n this.outputFormatter = options.outputFormatter;\n};\n\n/**\n * Should be used to determine name of the jsonrpc method based on arguments\n *\n * @method getCall\n * @param {Array} arguments\n * @return {String} name of jsonrpc method\n */\nMethod.prototype.getCall = function (args) {\n return utils.isFunction(this.call) ? this.call(args) : this.call;\n};\n\n/**\n * Should be used to extract callback from array of arguments. Modifies input param\n *\n * @method extractCallback\n * @param {Array} arguments\n * @return {Function|Null} callback, if exists\n */\nMethod.prototype.extractCallback = function (args) {\n if (utils.isFunction(args[args.length - 1])) {\n return args.pop(); // modify the args array!\n }\n};\n\n/**\n * Should be called to check if the number of arguments is correct\n * \n * @method validateArgs\n * @param {Array} arguments\n * @throws {Error} if it is not\n */\nMethod.prototype.validateArgs = function (args) {\n if (args.length !== this.params) {\n throw errors.InvalidNumberOfParams();\n }\n};\n\n/**\n * Should be called to format input args of method\n * \n * @method formatInput\n * @param {Array}\n * @return {Array}\n */\nMethod.prototype.formatInput = function (args) {\n if (!this.inputFormatter) {\n return args;\n }\n\n return this.inputFormatter.map(function (formatter, index) {\n return formatter ? formatter(args[index]) : args[index];\n });\n};\n\n/**\n * Should be called to format output(result) of method\n *\n * @method formatOutput\n * @param {Object}\n * @return {Object}\n */\nMethod.prototype.formatOutput = function (result) {\n return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;\n};\n\n/**\n * Should attach function to method\n * \n * @method attachToObject\n * @param {Object}\n * @param {Function}\n */\nMethod.prototype.attachToObject = function (obj) {\n var func = this.send.bind(this);\n func.request = this.request.bind(this);\n func.call = this.call; // that's ugly. filter.js uses it\n var name = this.name.split('.');\n if (name.length > 1) {\n obj[name[0]] = obj[name[0]] || {};\n obj[name[0]][name[1]] = func;\n } else {\n obj[name[0]] = func; \n }\n};\n\n/**\n * Should create payload from given input args\n *\n * @method toPayload\n * @param {Array} args\n * @return {Object}\n */\nMethod.prototype.toPayload = function (args) {\n var call = this.getCall(args);\n var callback = this.extractCallback(args);\n var params = this.formatInput(args);\n this.validateArgs(params);\n\n return {\n method: call,\n params: params,\n callback: callback\n };\n};\n\n/**\n * Should be called to create pure JSONRPC request which can be used in batch request\n *\n * @method request\n * @param {...} params\n * @return {Object} jsonrpc request\n */\nMethod.prototype.request = function () {\n var payload = this.toPayload(Array.prototype.slice.call(arguments));\n payload.format = this.formatOutput.bind(this);\n return payload;\n};\n\n/**\n * Should send request to the API\n *\n * @method send\n * @param list of params\n * @return result\n */\nMethod.prototype.send = function () {\n var payload = this.toPayload(Array.prototype.slice.call(arguments));\n if (payload.callback) {\n var self = this;\n return RequestManager.getInstance().sendAsync(payload, function (err, result) {\n payload.callback(err, self.formatOutput(result));\n });\n }\n return this.formatOutput(RequestManager.getInstance().send(payload));\n};\n\nmodule.exports = Method;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file method.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\nvar utils = require('../utils/utils');\nvar errors = require('./errors');\n\nvar Method = function (options) {\n this.name = options.name;\n this.call = options.call;\n this.params = options.params || 0;\n this.inputFormatter = options.inputFormatter;\n this.outputFormatter = options.outputFormatter;\n};\n\n/**\n * Should be used to determine name of the jsonrpc method based on arguments\n *\n * @method getCall\n * @param {Array} arguments\n * @return {String} name of jsonrpc method\n */\nMethod.prototype.getCall = function (args) {\n return utils.isFunction(this.call) ? this.call(args) : this.call;\n};\n\n/**\n * Should be used to extract callback from array of arguments. Modifies input param\n *\n * @method extractCallback\n * @param {Array} arguments\n * @return {Function|Null} callback, if exists\n */\nMethod.prototype.extractCallback = function (args) {\n if (utils.isFunction(args[args.length - 1])) {\n return args.pop(); // modify the args array!\n }\n};\n\n/**\n * Should be called to check if the number of arguments is correct\n * \n * @method validateArgs\n * @param {Array} arguments\n * @throws {Error} if it is not\n */\nMethod.prototype.validateArgs = function (args) {\n if (args.length !== this.params) {\n throw errors.InvalidNumberOfParams();\n }\n};\n\n/**\n * Should be called to format input args of method\n * \n * @method formatInput\n * @param {Array}\n * @return {Array}\n */\nMethod.prototype.formatInput = function (args) {\n if (!this.inputFormatter) {\n return args;\n }\n\n return this.inputFormatter.map(function (formatter, index) {\n return formatter ? formatter(args[index]) : args[index];\n });\n};\n\n/**\n * Should be called to format output(result) of method\n *\n * @method formatOutput\n * @param {Object}\n * @return {Object}\n */\nMethod.prototype.formatOutput = function (result) {\n return this.outputFormatter && result ? this.outputFormatter(result) : result;\n};\n\n/**\n * Should attach function to method\n * \n * @method attachToObject\n * @param {Object}\n * @param {Function}\n */\nMethod.prototype.attachToObject = function (obj) {\n var func = this.send.bind(this);\n func.request = this.request.bind(this);\n func.call = this.call; // that's ugly. filter.js uses it\n var name = this.name.split('.');\n if (name.length > 1) {\n obj[name[0]] = obj[name[0]] || {};\n obj[name[0]][name[1]] = func;\n } else {\n obj[name[0]] = func; \n }\n};\n\n/**\n * Should create payload from given input args\n *\n * @method toPayload\n * @param {Array} args\n * @return {Object}\n */\nMethod.prototype.toPayload = function (args) {\n var call = this.getCall(args);\n var callback = this.extractCallback(args);\n var params = this.formatInput(args);\n this.validateArgs(params);\n\n return {\n method: call,\n params: params,\n callback: callback\n };\n};\n\n/**\n * Should be called to create pure JSONRPC request which can be used in batch request\n *\n * @method request\n * @param {...} params\n * @return {Object} jsonrpc request\n */\nMethod.prototype.request = function () {\n var payload = this.toPayload(Array.prototype.slice.call(arguments));\n payload.format = this.formatOutput.bind(this);\n return payload;\n};\n\n/**\n * Should send request to the API\n *\n * @method send\n * @param list of params\n * @return result\n */\nMethod.prototype.send = function () {\n var payload = this.toPayload(Array.prototype.slice.call(arguments));\n if (payload.callback) {\n var self = this;\n return RequestManager.getInstance().sendAsync(payload, function (err, result) {\n payload.callback(err, self.formatOutput(result));\n });\n }\n return this.formatOutput(RequestManager.getInstance().send(payload));\n};\n\nmodule.exports = Method;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file namereg.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar contract = require('./contract');\n\nvar address = '0xc6d9d2cd449a754c494264e1809c50e34d64562b';\n\nvar abi = [\n {\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"name\",\"outputs\":[{\"name\":\"o_name\",\"type\":\"bytes32\"}],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"content\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"addr\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"reserve\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"subRegistrar\",\"outputs\":[{\"name\":\"o_subRegistrar\",\"type\":\"address\"}],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transfer\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_registrar\",\"type\":\"address\"}],\"name\":\"setSubRegistrar\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[],\"name\":\"Registrar\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_a\",\"type\":\"address\"},{\"name\":\"_primary\",\"type\":\"bool\"}],\"name\":\"setAddress\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_content\",\"type\":\"bytes32\"}],\"name\":\"setContent\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"disown\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"register\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},\n {\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"name\",\"type\":\"bytes32\"}],\"name\":\"Changed\",\"type\":\"event\"},\n {\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"name\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"PrimaryChanged\",\"type\":\"event\"}\n];\n\nmodule.exports = contract(abi).at(address);\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file eth.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar Property = require('./property');\n\n/// @returns an array of objects describing web3.eth api methods\nvar methods = [\n];\n\n/// @returns an array of objects describing web3.eth api properties\nvar properties = [\n new Property({\n name: 'listening',\n getter: 'net_listening'\n }),\n new Property({\n name: 'peerCount',\n getter: 'net_peerCount',\n outputFormatter: utils.toDecimal\n })\n];\n\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file property.js\n * @author Fabian Vogelsteller \n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\n\nvar Property = function (options) {\n this.name = options.name;\n this.getter = options.getter;\n this.setter = options.setter;\n this.outputFormatter = options.outputFormatter;\n this.inputFormatter = options.inputFormatter;\n};\n\n/**\n * Should be called to format input args of method\n * \n * @method formatInput\n * @param {Array}\n * @return {Array}\n */\nProperty.prototype.formatInput = function (arg) {\n return this.inputFormatter ? this.inputFormatter(arg) : arg;\n};\n\n/**\n * Should be called to format output(result) of method\n *\n * @method formatOutput\n * @param {Object}\n * @return {Object}\n */\nProperty.prototype.formatOutput = function (result) {\n return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;\n};\n\n/**\n * Should attach function to method\n * \n * @method attachToObject\n * @param {Object}\n * @param {Function}\n */\nProperty.prototype.attachToObject = function (obj) {\n var proto = {\n get: this.get.bind(this),\n };\n\n var names = this.name.split('.');\n var name = names[0];\n if (names.length > 1) {\n obj[names[0]] = obj[names[0]] || {};\n obj = obj[names[0]];\n name = names[1];\n }\n \n Object.defineProperty(obj, name, proto);\n\n var toAsyncName = function (prefix, name) {\n return prefix + name.charAt(0).toUpperCase() + name.slice(1);\n };\n\n obj[toAsyncName('get', name)] = this.getAsync.bind(this);\n};\n\n/**\n * Should be used to get value of the property\n *\n * @method get\n * @return {Object} value of the property\n */\nProperty.prototype.get = function () {\n return this.formatOutput(RequestManager.getInstance().send({\n method: this.getter\n }));\n};\n\n/**\n * Should be used to asynchrounously get value of property\n *\n * @method getAsync\n * @param {Function}\n */\nProperty.prototype.getAsync = function (callback) {\n var self = this;\n RequestManager.getInstance().sendAsync({\n method: this.getter\n }, function (err, result) {\n if (err) {\n return callback(err);\n }\n callback(err, self.formatOutput(result));\n });\n};\n\nmodule.exports = Property;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qtsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nvar QtSyncProvider = function () {\n};\n\nQtSyncProvider.prototype.send = function (payload) {\n var result = navigator.qt.callMethod(JSON.stringify(payload));\n return JSON.parse(result);\n};\n\nmodule.exports = QtSyncProvider;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file property.js\n * @author Fabian Vogelsteller \n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\nvar utils = require('../utils/utils');\n\nvar Property = function (options) {\n this.name = options.name;\n this.getter = options.getter;\n this.setter = options.setter;\n this.outputFormatter = options.outputFormatter;\n this.inputFormatter = options.inputFormatter;\n};\n\n/**\n * Should be called to format input args of method\n * \n * @method formatInput\n * @param {Array}\n * @return {Array}\n */\nProperty.prototype.formatInput = function (arg) {\n return this.inputFormatter ? this.inputFormatter(arg) : arg;\n};\n\n/**\n * Should be called to format output(result) of method\n *\n * @method formatOutput\n * @param {Object}\n * @return {Object}\n */\nProperty.prototype.formatOutput = function (result) {\n return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;\n};\n\n/**\n * Should be used to extract callback from array of arguments. Modifies input param\n *\n * @method extractCallback\n * @param {Array} arguments\n * @return {Function|Null} callback, if exists\n */\nProperty.prototype.extractCallback = function (args) {\n if (utils.isFunction(args[args.length - 1])) {\n return args.pop(); // modify the args array!\n }\n};\n\n/**\n * Should attach function to method\n * \n * @method attachToObject\n * @param {Object}\n * @param {Function}\n */\nProperty.prototype.attachToObject = function (obj) {\n var proto = {\n get: this.get.bind(this),\n };\n\n var names = this.name.split('.');\n var name = names[0];\n if (names.length > 1) {\n obj[names[0]] = obj[names[0]] || {};\n obj = obj[names[0]];\n name = names[1];\n }\n \n Object.defineProperty(obj, name, proto);\n\n var toAsyncName = function (prefix, name) {\n return prefix + name.charAt(0).toUpperCase() + name.slice(1);\n };\n\n var func = this.getAsync.bind(this);\n func.request = this.request.bind(this);\n\n obj[toAsyncName('get', name)] = func;\n};\n\n/**\n * Should be used to get value of the property\n *\n * @method get\n * @return {Object} value of the property\n */\nProperty.prototype.get = function () {\n return this.formatOutput(RequestManager.getInstance().send({\n method: this.getter\n }));\n};\n\n/**\n * Should be used to asynchrounously get value of property\n *\n * @method getAsync\n * @param {Function}\n */\nProperty.prototype.getAsync = function (callback) {\n var self = this;\n RequestManager.getInstance().sendAsync({\n method: this.getter\n }, function (err, result) {\n if (err) {\n return callback(err);\n }\n callback(err, self.formatOutput(result));\n });\n};\n\n/**\n * Should be called to create pure JSONRPC request which can be used in batch request\n *\n * @method request\n * @param {...} params\n * @return {Object} jsonrpc request\n */\nProperty.prototype.request = function () {\n var payload = {\n method: this.getter,\n params: [],\n callback: this.extractCallback(Array.prototype.slice.call(arguments))\n };\n payload.format = this.formatOutput.bind(this);\n return payload;\n};\n\nmodule.exports = Property;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file requestmanager.js\n * @author Jeffrey Wilcke \n * @author Marek Kotewicz \n * @author Marian Oancea \n * @author Fabian Vogelsteller \n * @author Gav Wood \n * @date 2014\n */\n\nvar Jsonrpc = require('./jsonrpc');\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar errors = require('./errors');\n\n/**\n * It's responsible for passing messages to providers\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 1 second\n * Singleton\n */\nvar RequestManager = function (provider) {\n // singleton pattern\n if (arguments.callee._singletonInstance) {\n return arguments.callee._singletonInstance;\n }\n arguments.callee._singletonInstance = this;\n\n this.provider = provider;\n this.polls = {};\n this.timeout = null;\n this.isPolling = false;\n};\n\n/**\n * @return {RequestManager} singleton\n */\nRequestManager.getInstance = function () {\n var instance = new RequestManager();\n return instance;\n};\n\n/**\n * Should be used to synchronously send request\n *\n * @method send\n * @param {Object} data\n * @return {Object}\n */\nRequestManager.prototype.send = function (data) {\n if (!this.provider) {\n console.error(errors.InvalidProvider());\n return null;\n }\n\n var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);\n var result = this.provider.send(payload);\n\n if (!Jsonrpc.getInstance().isValidResponse(result)) {\n throw errors.InvalidResponse(result);\n }\n\n return result.result;\n};\n\n/**\n * Should be used to asynchronously send request\n *\n * @method sendAsync\n * @param {Object} data\n * @param {Function} callback\n */\nRequestManager.prototype.sendAsync = function (data, callback) {\n if (!this.provider) {\n return callback(errors.InvalidProvider());\n }\n\n var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);\n this.provider.sendAsync(payload, function (err, result) {\n if (err) {\n return callback(err);\n }\n \n if (!Jsonrpc.getInstance().isValidResponse(result)) {\n return callback(errors.InvalidResponse(result));\n }\n\n callback(null, result.result);\n });\n};\n\n/**\n * Should be called to asynchronously send batch request\n *\n * @method sendBatch\n * @param {Array} batch data\n * @param {Function} callback\n */\nRequestManager.prototype.sendBatch = function (data, callback) {\n if (!this.provider) {\n return callback(errors.InvalidProvider());\n }\n\n var payload = Jsonrpc.getInstance().toBatchPayload(data);\n\n this.provider.sendAsync(payload, function (err, results) {\n if (err) {\n return callback(err);\n }\n\n if (!utils.isArray(results)) {\n return callback(errors.InvalidResponse(results));\n }\n\n callback(err, results);\n }); \n};\n\n/**\n * Should be used to set provider of request manager\n *\n * @method setProvider\n * @param {Object}\n */\nRequestManager.prototype.setProvider = function (p) {\n this.provider = p;\n\n if (this.provider && !this.isPolling) {\n this.poll();\n this.isPolling = true;\n }\n};\n\n/*jshint maxparams:4 */\n\n/**\n * Should be used to start polling\n *\n * @method startPolling\n * @param {Object} data\n * @param {Number} pollId\n * @param {Function} callback\n * @param {Function} uninstall\n *\n * @todo cleanup number of params\n */\nRequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {\n this.polls['poll_'+ pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall};\n};\n/*jshint maxparams:3 */\n\n/**\n * Should be used to stop polling for filter with given id\n *\n * @method stopPolling\n * @param {Number} pollId\n */\nRequestManager.prototype.stopPolling = function (pollId) {\n delete this.polls['poll_'+ pollId];\n};\n\n/**\n * Should be called to reset the polling mechanism of the request manager\n *\n * @method reset\n */\nRequestManager.prototype.reset = function () {\n for (var key in this.polls) {\n this.polls[key].uninstall();\n }\n this.polls = {};\n\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n this.poll();\n};\n\n/**\n * Should be called to poll for changes on filter with given id\n *\n * @method poll\n */\nRequestManager.prototype.poll = function () {\n /*jshint maxcomplexity: 6 */\n this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);\n\n if (Object.keys(this.polls).length === 0) {\n return;\n }\n\n if (!this.provider) {\n console.error(errors.InvalidProvider());\n return;\n }\n\n var pollsData = [];\n var pollsKeys = [];\n for (var key in this.polls) {\n pollsData.push(this.polls[key].data);\n pollsKeys.push(key);\n }\n\n if (pollsData.length === 0) {\n return;\n }\n\n var payload = Jsonrpc.getInstance().toBatchPayload(pollsData);\n\n var self = this;\n this.provider.sendAsync(payload, function (error, results) {\n // TODO: console log?\n if (error) {\n return;\n }\n\n if (!utils.isArray(results)) {\n throw errors.InvalidResponse(results);\n }\n\n results.map(function (result, index) {\n var key = pollsKeys[index];\n // make sure the filter is still installed after arrival of the request\n if (self.polls[key]) {\n result.callback = self.polls[key].callback;\n return result;\n } else\n return false;\n }).filter(function (result) {\n return !!result; \n }).filter(function (result) {\n var valid = Jsonrpc.getInstance().isValidResponse(result);\n if (!valid) {\n result.callback(errors.InvalidResponse(result));\n }\n return valid;\n }).filter(function (result) {\n return utils.isArray(result.result) && result.result.length > 0;\n }).forEach(function (result) {\n result.callback(null, result.result);\n });\n });\n};\n\nmodule.exports = RequestManager;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file shh.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\nvar formatters = require('./formatters');\n\nvar post = new Method({\n name: 'post', \n call: 'shh_post', \n params: 1,\n inputFormatter: [formatters.inputPostFormatter]\n});\n\nvar newIdentity = new Method({\n name: 'newIdentity',\n call: 'shh_newIdentity',\n params: 0\n});\n\nvar hasIdentity = new Method({\n name: 'hasIdentity',\n call: 'shh_hasIdentity',\n params: 1\n});\n\nvar newGroup = new Method({\n name: 'newGroup',\n call: 'shh_newGroup',\n params: 0\n});\n\nvar addToGroup = new Method({\n name: 'addToGroup',\n call: 'shh_addToGroup',\n params: 0\n});\n\nvar methods = [\n post,\n newIdentity,\n hasIdentity,\n newGroup,\n addToGroup\n];\n\nmodule.exports = {\n methods: methods\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file transfer.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar web3 = require('../web3');\nvar ICAP = require('./icap');\nvar namereg = require('./namereg');\nvar contract = require('./contract');\n\n/**\n * Should be used to make ICAP transfer\n *\n * @method transfer\n * @param {String} iban number\n * @param {String} from (address)\n * @param {Value} value to be tranfered\n * @param {Function} callback, callback\n */\nvar transfer = function (from, iban, value, callback) {\n var icap = new ICAP(iban); \n if (!icap.isValid()) {\n throw new Error('invalid iban address');\n }\n\n if (icap.isDirect()) {\n return transferToAddress(from, icap.address(), value, callback);\n }\n \n if (!callback) {\n var address = namereg.addr(icap.institution());\n return deposit(from, address, value, icap.client());\n }\n\n namereg.addr(icap.insitution(), function (err, address) {\n return deposit(from, address, value, icap.client(), callback);\n });\n \n};\n\n/**\n * Should be used to transfer funds to certain address\n *\n * @method transferToAddress\n * @param {String} address\n * @param {String} from (address)\n * @param {Value} value to be tranfered\n * @param {Function} callback, callback\n */\nvar transferToAddress = function (from, address, value, callback) {\n return web3.eth.sendTransaction({\n address: address,\n from: from,\n value: value\n }, callback);\n};\n\n/**\n * Should be used to deposit funds to generic Exchange contract (must implement deposit(bytes32) method!)\n *\n * @method deposit\n * @param {String} address\n * @param {String} from (address)\n * @param {Value} value to be tranfered\n * @param {String} client unique identifier\n * @param {Function} callback, callback\n */\nvar deposit = function (from, address, value, client, callback) {\n var abi = [{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"bytes32\"}],\"name\":\"deposit\",\"outputs\":[],\"type\":\"function\"}];\n return contract(abi).at(address).deposit(client, {\n from: from,\n value: value\n }, callback);\n};\n\nmodule.exports = transfer;\n\n", @@ -82,6 +82,6 @@ ";(function (root, factory, undef) {\n\tif (typeof exports === \"object\") {\n\t\t// CommonJS\n\t\tmodule.exports = exports = factory(require(\"./core\"), require(\"./x64-core\"));\n\t}\n\telse if (typeof define === \"function\" && define.amd) {\n\t\t// AMD\n\t\tdefine([\"./core\", \"./x64-core\"], factory);\n\t}\n\telse {\n\t\t// Global (browser)\n\t\tfactory(root.CryptoJS);\n\t}\n}(this, function (CryptoJS) {\n\n\t(function (Math) {\n\t // Shortcuts\n\t var C = CryptoJS;\n\t var C_lib = C.lib;\n\t var WordArray = C_lib.WordArray;\n\t var Hasher = C_lib.Hasher;\n\t var C_x64 = C.x64;\n\t var X64Word = C_x64.Word;\n\t var C_algo = C.algo;\n\n\t // Constants tables\n\t var RHO_OFFSETS = [];\n\t var PI_INDEXES = [];\n\t var ROUND_CONSTANTS = [];\n\n\t // Compute Constants\n\t (function () {\n\t // Compute rho offset constants\n\t var x = 1, y = 0;\n\t for (var t = 0; t < 24; t++) {\n\t RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64;\n\n\t var newX = y % 5;\n\t var newY = (2 * x + 3 * y) % 5;\n\t x = newX;\n\t y = newY;\n\t }\n\n\t // Compute pi index constants\n\t for (var x = 0; x < 5; x++) {\n\t for (var y = 0; y < 5; y++) {\n\t PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5;\n\t }\n\t }\n\n\t // Compute round constants\n\t var LFSR = 0x01;\n\t for (var i = 0; i < 24; i++) {\n\t var roundConstantMsw = 0;\n\t var roundConstantLsw = 0;\n\n\t for (var j = 0; j < 7; j++) {\n\t if (LFSR & 0x01) {\n\t var bitPosition = (1 << j) - 1;\n\t if (bitPosition < 32) {\n\t roundConstantLsw ^= 1 << bitPosition;\n\t } else /* if (bitPosition >= 32) */ {\n\t roundConstantMsw ^= 1 << (bitPosition - 32);\n\t }\n\t }\n\n\t // Compute next LFSR\n\t if (LFSR & 0x80) {\n\t // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1\n\t LFSR = (LFSR << 1) ^ 0x71;\n\t } else {\n\t LFSR <<= 1;\n\t }\n\t }\n\n\t ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw);\n\t }\n\t }());\n\n\t // Reusable objects for temporary values\n\t var T = [];\n\t (function () {\n\t for (var i = 0; i < 25; i++) {\n\t T[i] = X64Word.create();\n\t }\n\t }());\n\n\t /**\n\t * SHA-3 hash algorithm.\n\t */\n\t var SHA3 = C_algo.SHA3 = Hasher.extend({\n\t /**\n\t * Configuration options.\n\t *\n\t * @property {number} outputLength\n\t * The desired number of bits in the output hash.\n\t * Only values permitted are: 224, 256, 384, 512.\n\t * Default: 512\n\t */\n\t cfg: Hasher.cfg.extend({\n\t outputLength: 512\n\t }),\n\n\t _doReset: function () {\n\t var state = this._state = []\n\t for (var i = 0; i < 25; i++) {\n\t state[i] = new X64Word.init();\n\t }\n\n\t this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32;\n\t },\n\n\t _doProcessBlock: function (M, offset) {\n\t // Shortcuts\n\t var state = this._state;\n\t var nBlockSizeLanes = this.blockSize / 2;\n\n\t // Absorb\n\t for (var i = 0; i < nBlockSizeLanes; i++) {\n\t // Shortcuts\n\t var M2i = M[offset + 2 * i];\n\t var M2i1 = M[offset + 2 * i + 1];\n\n\t // Swap endian\n\t M2i = (\n\t (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) |\n\t (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00)\n\t );\n\t M2i1 = (\n\t (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) |\n\t (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00)\n\t );\n\n\t // Absorb message into state\n\t var lane = state[i];\n\t lane.high ^= M2i1;\n\t lane.low ^= M2i;\n\t }\n\n\t // Rounds\n\t for (var round = 0; round < 24; round++) {\n\t // Theta\n\t for (var x = 0; x < 5; x++) {\n\t // Mix column lanes\n\t var tMsw = 0, tLsw = 0;\n\t for (var y = 0; y < 5; y++) {\n\t var lane = state[x + 5 * y];\n\t tMsw ^= lane.high;\n\t tLsw ^= lane.low;\n\t }\n\n\t // Temporary values\n\t var Tx = T[x];\n\t Tx.high = tMsw;\n\t Tx.low = tLsw;\n\t }\n\t for (var x = 0; x < 5; x++) {\n\t // Shortcuts\n\t var Tx4 = T[(x + 4) % 5];\n\t var Tx1 = T[(x + 1) % 5];\n\t var Tx1Msw = Tx1.high;\n\t var Tx1Lsw = Tx1.low;\n\n\t // Mix surrounding columns\n\t var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));\n\t var tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));\n\t for (var y = 0; y < 5; y++) {\n\t var lane = state[x + 5 * y];\n\t lane.high ^= tMsw;\n\t lane.low ^= tLsw;\n\t }\n\t }\n\n\t // Rho Pi\n\t for (var laneIndex = 1; laneIndex < 25; laneIndex++) {\n\t // Shortcuts\n\t var lane = state[laneIndex];\n\t var laneMsw = lane.high;\n\t var laneLsw = lane.low;\n\t var rhoOffset = RHO_OFFSETS[laneIndex];\n\n\t // Rotate lanes\n\t if (rhoOffset < 32) {\n\t var tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));\n\t var tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));\n\t } else /* if (rhoOffset >= 32) */ {\n\t var tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));\n\t var tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));\n\t }\n\n\t // Transpose lanes\n\t var TPiLane = T[PI_INDEXES[laneIndex]];\n\t TPiLane.high = tMsw;\n\t TPiLane.low = tLsw;\n\t }\n\n\t // Rho pi at x = y = 0\n\t var T0 = T[0];\n\t var state0 = state[0];\n\t T0.high = state0.high;\n\t T0.low = state0.low;\n\n\t // Chi\n\t for (var x = 0; x < 5; x++) {\n\t for (var y = 0; y < 5; y++) {\n\t // Shortcuts\n\t var laneIndex = x + 5 * y;\n\t var lane = state[laneIndex];\n\t var TLane = T[laneIndex];\n\t var Tx1Lane = T[((x + 1) % 5) + 5 * y];\n\t var Tx2Lane = T[((x + 2) % 5) + 5 * y];\n\n\t // Mix rows\n\t lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);\n\t lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low);\n\t }\n\t }\n\n\t // Iota\n\t var lane = state[0];\n\t var roundConstant = ROUND_CONSTANTS[round];\n\t lane.high ^= roundConstant.high;\n\t lane.low ^= roundConstant.low;;\n\t }\n\t },\n\n\t _doFinalize: function () {\n\t // Shortcuts\n\t var data = this._data;\n\t var dataWords = data.words;\n\t var nBitsTotal = this._nDataBytes * 8;\n\t var nBitsLeft = data.sigBytes * 8;\n\t var blockSizeBits = this.blockSize * 32;\n\n\t // Add padding\n\t dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32);\n\t dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;\n\t data.sigBytes = dataWords.length * 4;\n\n\t // Hash final blocks\n\t this._process();\n\n\t // Shortcuts\n\t var state = this._state;\n\t var outputLengthBytes = this.cfg.outputLength / 8;\n\t var outputLengthLanes = outputLengthBytes / 8;\n\n\t // Squeeze\n\t var hashWords = [];\n\t for (var i = 0; i < outputLengthLanes; i++) {\n\t // Shortcuts\n\t var lane = state[i];\n\t var laneMsw = lane.high;\n\t var laneLsw = lane.low;\n\n\t // Swap endian\n\t laneMsw = (\n\t (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) |\n\t (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00)\n\t );\n\t laneLsw = (\n\t (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) |\n\t (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00)\n\t );\n\n\t // Squeeze state to retrieve hash\n\t hashWords.push(laneLsw);\n\t hashWords.push(laneMsw);\n\t }\n\n\t // Return final computed hash\n\t return new WordArray.init(hashWords, outputLengthBytes);\n\t },\n\n\t clone: function () {\n\t var clone = Hasher.clone.call(this);\n\n\t var state = clone._state = this._state.slice(0);\n\t for (var i = 0; i < 25; i++) {\n\t state[i] = state[i].clone();\n\t }\n\n\t return clone;\n\t }\n\t });\n\n\t /**\n\t * Shortcut function to the hasher's object interface.\n\t *\n\t * @param {WordArray|string} message The message to hash.\n\t *\n\t * @return {WordArray} The hash.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var hash = CryptoJS.SHA3('message');\n\t * var hash = CryptoJS.SHA3(wordArray);\n\t */\n\t C.SHA3 = Hasher._createHelper(SHA3);\n\n\t /**\n\t * Shortcut function to the HMAC's object interface.\n\t *\n\t * @param {WordArray|string} message The message to hash.\n\t * @param {WordArray|string} key The secret key.\n\t *\n\t * @return {WordArray} The HMAC.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var hmac = CryptoJS.HmacSHA3(message, key);\n\t */\n\t C.HmacSHA3 = Hasher._createHmacHelper(SHA3);\n\t}(Math));\n\n\n\treturn CryptoJS.SHA3;\n\n}));", ";(function (root, factory) {\n\tif (typeof exports === \"object\") {\n\t\t// CommonJS\n\t\tmodule.exports = exports = factory(require(\"./core\"));\n\t}\n\telse if (typeof define === \"function\" && define.amd) {\n\t\t// AMD\n\t\tdefine([\"./core\"], factory);\n\t}\n\telse {\n\t\t// Global (browser)\n\t\tfactory(root.CryptoJS);\n\t}\n}(this, function (CryptoJS) {\n\n\t(function (undefined) {\n\t // Shortcuts\n\t var C = CryptoJS;\n\t var C_lib = C.lib;\n\t var Base = C_lib.Base;\n\t var X32WordArray = C_lib.WordArray;\n\n\t /**\n\t * x64 namespace.\n\t */\n\t var C_x64 = C.x64 = {};\n\n\t /**\n\t * A 64-bit word.\n\t */\n\t var X64Word = C_x64.Word = Base.extend({\n\t /**\n\t * Initializes a newly created 64-bit word.\n\t *\n\t * @param {number} high The high 32 bits.\n\t * @param {number} low The low 32 bits.\n\t *\n\t * @example\n\t *\n\t * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607);\n\t */\n\t init: function (high, low) {\n\t this.high = high;\n\t this.low = low;\n\t }\n\n\t /**\n\t * Bitwise NOTs this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after negating.\n\t *\n\t * @example\n\t *\n\t * var negated = x64Word.not();\n\t */\n\t // not: function () {\n\t // var high = ~this.high;\n\t // var low = ~this.low;\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Bitwise ANDs this word with the passed word.\n\t *\n\t * @param {X64Word} word The x64-Word to AND with this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after ANDing.\n\t *\n\t * @example\n\t *\n\t * var anded = x64Word.and(anotherX64Word);\n\t */\n\t // and: function (word) {\n\t // var high = this.high & word.high;\n\t // var low = this.low & word.low;\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Bitwise ORs this word with the passed word.\n\t *\n\t * @param {X64Word} word The x64-Word to OR with this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after ORing.\n\t *\n\t * @example\n\t *\n\t * var ored = x64Word.or(anotherX64Word);\n\t */\n\t // or: function (word) {\n\t // var high = this.high | word.high;\n\t // var low = this.low | word.low;\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Bitwise XORs this word with the passed word.\n\t *\n\t * @param {X64Word} word The x64-Word to XOR with this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after XORing.\n\t *\n\t * @example\n\t *\n\t * var xored = x64Word.xor(anotherX64Word);\n\t */\n\t // xor: function (word) {\n\t // var high = this.high ^ word.high;\n\t // var low = this.low ^ word.low;\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Shifts this word n bits to the left.\n\t *\n\t * @param {number} n The number of bits to shift.\n\t *\n\t * @return {X64Word} A new x64-Word object after shifting.\n\t *\n\t * @example\n\t *\n\t * var shifted = x64Word.shiftL(25);\n\t */\n\t // shiftL: function (n) {\n\t // if (n < 32) {\n\t // var high = (this.high << n) | (this.low >>> (32 - n));\n\t // var low = this.low << n;\n\t // } else {\n\t // var high = this.low << (n - 32);\n\t // var low = 0;\n\t // }\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Shifts this word n bits to the right.\n\t *\n\t * @param {number} n The number of bits to shift.\n\t *\n\t * @return {X64Word} A new x64-Word object after shifting.\n\t *\n\t * @example\n\t *\n\t * var shifted = x64Word.shiftR(7);\n\t */\n\t // shiftR: function (n) {\n\t // if (n < 32) {\n\t // var low = (this.low >>> n) | (this.high << (32 - n));\n\t // var high = this.high >>> n;\n\t // } else {\n\t // var low = this.high >>> (n - 32);\n\t // var high = 0;\n\t // }\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Rotates this word n bits to the left.\n\t *\n\t * @param {number} n The number of bits to rotate.\n\t *\n\t * @return {X64Word} A new x64-Word object after rotating.\n\t *\n\t * @example\n\t *\n\t * var rotated = x64Word.rotL(25);\n\t */\n\t // rotL: function (n) {\n\t // return this.shiftL(n).or(this.shiftR(64 - n));\n\t // },\n\n\t /**\n\t * Rotates this word n bits to the right.\n\t *\n\t * @param {number} n The number of bits to rotate.\n\t *\n\t * @return {X64Word} A new x64-Word object after rotating.\n\t *\n\t * @example\n\t *\n\t * var rotated = x64Word.rotR(7);\n\t */\n\t // rotR: function (n) {\n\t // return this.shiftR(n).or(this.shiftL(64 - n));\n\t // },\n\n\t /**\n\t * Adds this word with the passed word.\n\t *\n\t * @param {X64Word} word The x64-Word to add with this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after adding.\n\t *\n\t * @example\n\t *\n\t * var added = x64Word.add(anotherX64Word);\n\t */\n\t // add: function (word) {\n\t // var low = (this.low + word.low) | 0;\n\t // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0;\n\t // var high = (this.high + word.high + carry) | 0;\n\n\t // return X64Word.create(high, low);\n\t // }\n\t });\n\n\t /**\n\t * An array of 64-bit words.\n\t *\n\t * @property {Array} words The array of CryptoJS.x64.Word objects.\n\t * @property {number} sigBytes The number of significant bytes in this word array.\n\t */\n\t var X64WordArray = C_x64.WordArray = Base.extend({\n\t /**\n\t * Initializes a newly created word array.\n\t *\n\t * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects.\n\t * @param {number} sigBytes (Optional) The number of significant bytes in the words.\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.x64.WordArray.create();\n\t *\n\t * var wordArray = CryptoJS.x64.WordArray.create([\n\t * CryptoJS.x64.Word.create(0x00010203, 0x04050607),\n\t * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)\n\t * ]);\n\t *\n\t * var wordArray = CryptoJS.x64.WordArray.create([\n\t * CryptoJS.x64.Word.create(0x00010203, 0x04050607),\n\t * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)\n\t * ], 10);\n\t */\n\t init: function (words, sigBytes) {\n\t words = this.words = words || [];\n\n\t if (sigBytes != undefined) {\n\t this.sigBytes = sigBytes;\n\t } else {\n\t this.sigBytes = words.length * 8;\n\t }\n\t },\n\n\t /**\n\t * Converts this 64-bit word array to a 32-bit word array.\n\t *\n\t * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array.\n\t *\n\t * @example\n\t *\n\t * var x32WordArray = x64WordArray.toX32();\n\t */\n\t toX32: function () {\n\t // Shortcuts\n\t var x64Words = this.words;\n\t var x64WordsLength = x64Words.length;\n\n\t // Convert\n\t var x32Words = [];\n\t for (var i = 0; i < x64WordsLength; i++) {\n\t var x64Word = x64Words[i];\n\t x32Words.push(x64Word.high);\n\t x32Words.push(x64Word.low);\n\t }\n\n\t return X32WordArray.create(x32Words, this.sigBytes);\n\t },\n\n\t /**\n\t * Creates a copy of this word array.\n\t *\n\t * @return {X64WordArray} The clone.\n\t *\n\t * @example\n\t *\n\t * var clone = x64WordArray.clone();\n\t */\n\t clone: function () {\n\t var clone = Base.clone.call(this);\n\n\t // Clone \"words\" array\n\t var words = clone.words = this.words.slice(0);\n\n\t // Clone each X64Word object\n\t var wordsLength = words.length;\n\t for (var i = 0; i < wordsLength; i++) {\n\t words[i] = words[i].clone();\n\t }\n\n\t return clone;\n\t }\n\t });\n\t}());\n\n\n\treturn CryptoJS;\n\n}));", "/*! bignumber.js v2.0.7 https://github.com/MikeMcl/bignumber.js/LICENCE */\n\n;(function (global) {\n 'use strict';\n\n /*\n bignumber.js v2.0.7\n A JavaScript library for arbitrary-precision arithmetic.\n https://github.com/MikeMcl/bignumber.js\n Copyright (c) 2015 Michael Mclaughlin \n MIT Expat Licence\n */\n\n\n var BigNumber, crypto, parseNumeric,\n isNumeric = /^-?(\\d+(\\.\\d*)?|\\.\\d+)(e[+-]?\\d+)?$/i,\n mathceil = Math.ceil,\n mathfloor = Math.floor,\n notBool = ' not a boolean or binary digit',\n roundingMode = 'rounding mode',\n tooManyDigits = 'number type has more than 15 significant digits',\n ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_',\n BASE = 1e14,\n LOG_BASE = 14,\n MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1\n // MAX_INT32 = 0x7fffffff, // 2^31 - 1\n POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13],\n SQRT_BASE = 1e7,\n\n /*\n * The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and\n * the arguments to toExponential, toFixed, toFormat, and toPrecision, beyond which an\n * exception is thrown (if ERRORS is true).\n */\n MAX = 1E9; // 0 to MAX_INT32\n\n\n /*\n * Create and return a BigNumber constructor.\n */\n function another(configObj) {\n var div,\n\n // id tracks the caller function, so its name can be included in error messages.\n id = 0,\n P = BigNumber.prototype,\n ONE = new BigNumber(1),\n\n\n /********************************* EDITABLE DEFAULTS **********************************/\n\n\n /*\n * The default values below must be integers within the inclusive ranges stated.\n * The values can also be changed at run-time using BigNumber.config.\n */\n\n // The maximum number of decimal places for operations involving division.\n DECIMAL_PLACES = 20, // 0 to MAX\n\n /*\n * The rounding mode used when rounding to the above decimal places, and when using\n * toExponential, toFixed, toFormat and toPrecision, and round (default value).\n * UP 0 Away from zero.\n * DOWN 1 Towards zero.\n * CEIL 2 Towards +Infinity.\n * FLOOR 3 Towards -Infinity.\n * HALF_UP 4 Towards nearest neighbour. If equidistant, up.\n * HALF_DOWN 5 Towards nearest neighbour. If equidistant, down.\n * HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour.\n * HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity.\n * HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity.\n */\n ROUNDING_MODE = 4, // 0 to 8\n\n // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS]\n\n // The exponent value at and beneath which toString returns exponential notation.\n // Number type: -7\n TO_EXP_NEG = -7, // 0 to -MAX\n\n // The exponent value at and above which toString returns exponential notation.\n // Number type: 21\n TO_EXP_POS = 21, // 0 to MAX\n\n // RANGE : [MIN_EXP, MAX_EXP]\n\n // The minimum exponent value, beneath which underflow to zero occurs.\n // Number type: -324 (5e-324)\n MIN_EXP = -1e7, // -1 to -MAX\n\n // The maximum exponent value, above which overflow to Infinity occurs.\n // Number type: 308 (1.7976931348623157e+308)\n // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow.\n MAX_EXP = 1e7, // 1 to MAX\n\n // Whether BigNumber Errors are ever thrown.\n ERRORS = true, // true or false\n\n // Change to intValidatorNoErrors if ERRORS is false.\n isValidInt = intValidatorWithErrors, // intValidatorWithErrors/intValidatorNoErrors\n\n // Whether to use cryptographically-secure random number generation, if available.\n CRYPTO = false, // true or false\n\n /*\n * The modulo mode used when calculating the modulus: a mod n.\n * The quotient (q = a / n) is calculated according to the corresponding rounding mode.\n * The remainder (r) is calculated as: r = a - n * q.\n *\n * UP 0 The remainder is positive if the dividend is negative, else is negative.\n * DOWN 1 The remainder has the same sign as the dividend.\n * This modulo mode is commonly known as 'truncated division' and is\n * equivalent to (a % n) in JavaScript.\n * FLOOR 3 The remainder has the same sign as the divisor (Python %).\n * HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function.\n * EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)).\n * The remainder is always positive.\n *\n * The truncated division, floored division, Euclidian division and IEEE 754 remainder\n * modes are commonly used for the modulus operation.\n * Although the other rounding modes can also be used, they may not give useful results.\n */\n MODULO_MODE = 1, // 0 to 9\n\n // The maximum number of significant digits of the result of the toPower operation.\n // If POW_PRECISION is 0, there will be unlimited significant digits.\n POW_PRECISION = 100, // 0 to MAX\n\n // The format specification used by the BigNumber.prototype.toFormat method.\n FORMAT = {\n decimalSeparator: '.',\n groupSeparator: ',',\n groupSize: 3,\n secondaryGroupSize: 0,\n fractionGroupSeparator: '\\xA0', // non-breaking space\n fractionGroupSize: 0\n };\n\n\n /******************************************************************************************/\n\n\n // CONSTRUCTOR\n\n\n /*\n * The BigNumber constructor and exported function.\n * Create and return a new instance of a BigNumber object.\n *\n * n {number|string|BigNumber} A numeric value.\n * [b] {number} The base of n. Integer, 2 to 64 inclusive.\n */\n function BigNumber( n, b ) {\n var c, e, i, num, len, str,\n x = this;\n\n // Enable constructor usage without new.\n if ( !( x instanceof BigNumber ) ) {\n\n // 'BigNumber() constructor call without new: {n}'\n if (ERRORS) raise( 26, 'constructor call without new', n );\n return new BigNumber( n, b );\n }\n\n // 'new BigNumber() base not an integer: {b}'\n // 'new BigNumber() base out of range: {b}'\n if ( b == null || !isValidInt( b, 2, 64, id, 'base' ) ) {\n\n // Duplicate.\n if ( n instanceof BigNumber ) {\n x.s = n.s;\n x.e = n.e;\n x.c = ( n = n.c ) ? n.slice() : n;\n id = 0;\n return;\n }\n\n if ( ( num = typeof n == 'number' ) && n * 0 == 0 ) {\n x.s = 1 / n < 0 ? ( n = -n, -1 ) : 1;\n\n // Fast path for integers.\n if ( n === ~~n ) {\n for ( e = 0, i = n; i >= 10; i /= 10, e++ );\n x.e = e;\n x.c = [n];\n id = 0;\n return;\n }\n\n str = n + '';\n } else {\n if ( !isNumeric.test( str = n + '' ) ) return parseNumeric( x, str, num );\n x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1;\n }\n } else {\n b = b | 0;\n str = n + '';\n\n // Ensure return value is rounded to DECIMAL_PLACES as with other bases.\n // Allow exponential notation to be used with base 10 argument.\n if ( b == 10 ) {\n x = new BigNumber( n instanceof BigNumber ? n : str );\n return round( x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE );\n }\n\n // Avoid potential interpretation of Infinity and NaN as base 44+ values.\n // Any number in exponential form will fail due to the [Ee][+-].\n if ( ( num = typeof n == 'number' ) && n * 0 != 0 ||\n !( new RegExp( '^-?' + ( c = '[' + ALPHABET.slice( 0, b ) + ']+' ) +\n '(?:\\\\.' + c + ')?$',b < 37 ? 'i' : '' ) ).test(str) ) {\n return parseNumeric( x, str, num, b );\n }\n\n if (num) {\n x.s = 1 / n < 0 ? ( str = str.slice(1), -1 ) : 1;\n\n if ( ERRORS && str.replace( /^0\\.0*|\\./, '' ).length > 15 ) {\n\n // 'new BigNumber() number type has more than 15 significant digits: {n}'\n raise( id, tooManyDigits, n );\n }\n\n // Prevent later check for length on converted number.\n num = false;\n } else {\n x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1;\n }\n\n str = convertBase( str, 10, b, x.s );\n }\n\n // Decimal point?\n if ( ( e = str.indexOf('.') ) > -1 ) str = str.replace( '.', '' );\n\n // Exponential form?\n if ( ( i = str.search( /e/i ) ) > 0 ) {\n\n // Determine exponent.\n if ( e < 0 ) e = i;\n e += +str.slice( i + 1 );\n str = str.substring( 0, i );\n } else if ( e < 0 ) {\n\n // Integer.\n e = str.length;\n }\n\n // Determine leading zeros.\n for ( i = 0; str.charCodeAt(i) === 48; i++ );\n\n // Determine trailing zeros.\n for ( len = str.length; str.charCodeAt(--len) === 48; );\n str = str.slice( i, len + 1 );\n\n if (str) {\n len = str.length;\n\n // Disallow numbers with over 15 significant digits if number type.\n // 'new BigNumber() number type has more than 15 significant digits: {n}'\n if ( num && ERRORS && len > 15 ) raise( id, tooManyDigits, x.s * n );\n\n e = e - i - 1;\n\n // Overflow?\n if ( e > MAX_EXP ) {\n\n // Infinity.\n x.c = x.e = null;\n\n // Underflow?\n } else if ( e < MIN_EXP ) {\n\n // Zero.\n x.c = [ x.e = 0 ];\n } else {\n x.e = e;\n x.c = [];\n\n // Transform base\n\n // e is the base 10 exponent.\n // i is where to slice str to get the first element of the coefficient array.\n i = ( e + 1 ) % LOG_BASE;\n if ( e < 0 ) i += LOG_BASE;\n\n if ( i < len ) {\n if (i) x.c.push( +str.slice( 0, i ) );\n\n for ( len -= LOG_BASE; i < len; ) {\n x.c.push( +str.slice( i, i += LOG_BASE ) );\n }\n\n str = str.slice(i);\n i = LOG_BASE - str.length;\n } else {\n i -= len;\n }\n\n for ( ; i--; str += '0' );\n x.c.push( +str );\n }\n } else {\n\n // Zero.\n x.c = [ x.e = 0 ];\n }\n\n id = 0;\n }\n\n\n // CONSTRUCTOR PROPERTIES\n\n\n BigNumber.another = another;\n\n BigNumber.ROUND_UP = 0;\n BigNumber.ROUND_DOWN = 1;\n BigNumber.ROUND_CEIL = 2;\n BigNumber.ROUND_FLOOR = 3;\n BigNumber.ROUND_HALF_UP = 4;\n BigNumber.ROUND_HALF_DOWN = 5;\n BigNumber.ROUND_HALF_EVEN = 6;\n BigNumber.ROUND_HALF_CEIL = 7;\n BigNumber.ROUND_HALF_FLOOR = 8;\n BigNumber.EUCLID = 9;\n\n\n /*\n * Configure infrequently-changing library-wide settings.\n *\n * Accept an object or an argument list, with one or many of the following properties or\n * parameters respectively:\n *\n * DECIMAL_PLACES {number} Integer, 0 to MAX inclusive\n * ROUNDING_MODE {number} Integer, 0 to 8 inclusive\n * EXPONENTIAL_AT {number|number[]} Integer, -MAX to MAX inclusive or\n * [integer -MAX to 0 incl., 0 to MAX incl.]\n * RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or\n * [integer -MAX to -1 incl., integer 1 to MAX incl.]\n * ERRORS {boolean|number} true, false, 1 or 0\n * CRYPTO {boolean|number} true, false, 1 or 0\n * MODULO_MODE {number} 0 to 9 inclusive\n * POW_PRECISION {number} 0 to MAX inclusive\n * FORMAT {object} See BigNumber.prototype.toFormat\n * decimalSeparator {string}\n * groupSeparator {string}\n * groupSize {number}\n * secondaryGroupSize {number}\n * fractionGroupSeparator {string}\n * fractionGroupSize {number}\n *\n * (The values assigned to the above FORMAT object properties are not checked for validity.)\n *\n * E.g.\n * BigNumber.config(20, 4) is equivalent to\n * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 })\n *\n * Ignore properties/parameters set to null or undefined.\n * Return an object with the properties current values.\n */\n BigNumber.config = function () {\n var v, p,\n i = 0,\n r = {},\n a = arguments,\n o = a[0],\n has = o && typeof o == 'object'\n ? function () { if ( o.hasOwnProperty(p) ) return ( v = o[p] ) != null; }\n : function () { if ( a.length > i ) return ( v = a[i++] ) != null; };\n\n // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive.\n // 'config() DECIMAL_PLACES not an integer: {v}'\n // 'config() DECIMAL_PLACES out of range: {v}'\n if ( has( p = 'DECIMAL_PLACES' ) && isValidInt( v, 0, MAX, 2, p ) ) {\n DECIMAL_PLACES = v | 0;\n }\n r[p] = DECIMAL_PLACES;\n\n // ROUNDING_MODE {number} Integer, 0 to 8 inclusive.\n // 'config() ROUNDING_MODE not an integer: {v}'\n // 'config() ROUNDING_MODE out of range: {v}'\n if ( has( p = 'ROUNDING_MODE' ) && isValidInt( v, 0, 8, 2, p ) ) {\n ROUNDING_MODE = v | 0;\n }\n r[p] = ROUNDING_MODE;\n\n // EXPONENTIAL_AT {number|number[]}\n // Integer, -MAX to MAX inclusive or [integer -MAX to 0 inclusive, 0 to MAX inclusive].\n // 'config() EXPONENTIAL_AT not an integer: {v}'\n // 'config() EXPONENTIAL_AT out of range: {v}'\n if ( has( p = 'EXPONENTIAL_AT' ) ) {\n\n if ( isArray(v) ) {\n if ( isValidInt( v[0], -MAX, 0, 2, p ) && isValidInt( v[1], 0, MAX, 2, p ) ) {\n TO_EXP_NEG = v[0] | 0;\n TO_EXP_POS = v[1] | 0;\n }\n } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) {\n TO_EXP_NEG = -( TO_EXP_POS = ( v < 0 ? -v : v ) | 0 );\n }\n }\n r[p] = [ TO_EXP_NEG, TO_EXP_POS ];\n\n // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or\n // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive].\n // 'config() RANGE not an integer: {v}'\n // 'config() RANGE cannot be zero: {v}'\n // 'config() RANGE out of range: {v}'\n if ( has( p = 'RANGE' ) ) {\n\n if ( isArray(v) ) {\n if ( isValidInt( v[0], -MAX, -1, 2, p ) && isValidInt( v[1], 1, MAX, 2, p ) ) {\n MIN_EXP = v[0] | 0;\n MAX_EXP = v[1] | 0;\n }\n } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) {\n if ( v | 0 ) MIN_EXP = -( MAX_EXP = ( v < 0 ? -v : v ) | 0 );\n else if (ERRORS) raise( 2, p + ' cannot be zero', v );\n }\n }\n r[p] = [ MIN_EXP, MAX_EXP ];\n\n // ERRORS {boolean|number} true, false, 1 or 0.\n // 'config() ERRORS not a boolean or binary digit: {v}'\n if ( has( p = 'ERRORS' ) ) {\n\n if ( v === !!v || v === 1 || v === 0 ) {\n id = 0;\n isValidInt = ( ERRORS = !!v ) ? intValidatorWithErrors : intValidatorNoErrors;\n } else if (ERRORS) {\n raise( 2, p + notBool, v );\n }\n }\n r[p] = ERRORS;\n\n // CRYPTO {boolean|number} true, false, 1 or 0.\n // 'config() CRYPTO not a boolean or binary digit: {v}'\n // 'config() crypto unavailable: {crypto}'\n if ( has( p = 'CRYPTO' ) ) {\n\n if ( v === !!v || v === 1 || v === 0 ) {\n CRYPTO = !!( v && crypto && typeof crypto == 'object' );\n if ( v && !CRYPTO && ERRORS ) raise( 2, 'crypto unavailable', crypto );\n } else if (ERRORS) {\n raise( 2, p + notBool, v );\n }\n }\n r[p] = CRYPTO;\n\n // MODULO_MODE {number} Integer, 0 to 9 inclusive.\n // 'config() MODULO_MODE not an integer: {v}'\n // 'config() MODULO_MODE out of range: {v}'\n if ( has( p = 'MODULO_MODE' ) && isValidInt( v, 0, 9, 2, p ) ) {\n MODULO_MODE = v | 0;\n }\n r[p] = MODULO_MODE;\n\n // POW_PRECISION {number} Integer, 0 to MAX inclusive.\n // 'config() POW_PRECISION not an integer: {v}'\n // 'config() POW_PRECISION out of range: {v}'\n if ( has( p = 'POW_PRECISION' ) && isValidInt( v, 0, MAX, 2, p ) ) {\n POW_PRECISION = v | 0;\n }\n r[p] = POW_PRECISION;\n\n // FORMAT {object}\n // 'config() FORMAT not an object: {v}'\n if ( has( p = 'FORMAT' ) ) {\n\n if ( typeof v == 'object' ) {\n FORMAT = v;\n } else if (ERRORS) {\n raise( 2, p + ' not an object', v );\n }\n }\n r[p] = FORMAT;\n\n return r;\n };\n\n\n /*\n * Return a new BigNumber whose value is the maximum of the arguments.\n *\n * arguments {number|string|BigNumber}\n */\n BigNumber.max = function () { return maxOrMin( arguments, P.lt ); };\n\n\n /*\n * Return a new BigNumber whose value is the minimum of the arguments.\n *\n * arguments {number|string|BigNumber}\n */\n BigNumber.min = function () { return maxOrMin( arguments, P.gt ); };\n\n\n /*\n * Return a new BigNumber with a random value equal to or greater than 0 and less than 1,\n * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing\n * zeros are produced).\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n *\n * 'random() decimal places not an integer: {dp}'\n * 'random() decimal places out of range: {dp}'\n * 'random() crypto unavailable: {crypto}'\n */\n BigNumber.random = (function () {\n var pow2_53 = 0x20000000000000;\n\n // Return a 53 bit integer n, where 0 <= n < 9007199254740992.\n // Check if Math.random() produces more than 32 bits of randomness.\n // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits.\n // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1.\n var random53bitInt = (Math.random() * pow2_53) & 0x1fffff\n ? function () { return mathfloor( Math.random() * pow2_53 ); }\n : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) +\n (Math.random() * 0x800000 | 0); };\n\n return function (dp) {\n var a, b, e, k, v,\n i = 0,\n c = [],\n rand = new BigNumber(ONE);\n\n dp = dp == null || !isValidInt( dp, 0, MAX, 14 ) ? DECIMAL_PLACES : dp | 0;\n k = mathceil( dp / LOG_BASE );\n\n if (CRYPTO) {\n\n // Browsers supporting crypto.getRandomValues.\n if ( crypto && crypto.getRandomValues ) {\n\n a = crypto.getRandomValues( new Uint32Array( k *= 2 ) );\n\n for ( ; i < k; ) {\n\n // 53 bits:\n // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2)\n // 11111 11111111 11111111 11111111 11100000 00000000 00000000\n // ((Math.pow(2, 32) - 1) >>> 11).toString(2)\n // 11111 11111111 11111111\n // 0x20000 is 2^21.\n v = a[i] * 0x20000 + (a[i + 1] >>> 11);\n\n // Rejection sampling:\n // 0 <= v < 9007199254740992\n // Probability that v >= 9e15, is\n // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251\n if ( v >= 9e15 ) {\n b = crypto.getRandomValues( new Uint32Array(2) );\n a[i] = b[0];\n a[i + 1] = b[1];\n } else {\n\n // 0 <= v <= 8999999999999999\n // 0 <= (v % 1e14) <= 99999999999999\n c.push( v % 1e14 );\n i += 2;\n }\n }\n i = k / 2;\n\n // Node.js supporting crypto.randomBytes.\n } else if ( crypto && crypto.randomBytes ) {\n\n // buffer\n a = crypto.randomBytes( k *= 7 );\n\n for ( ; i < k; ) {\n\n // 0x1000000000000 is 2^48, 0x10000000000 is 2^40\n // 0x100000000 is 2^32, 0x1000000 is 2^24\n // 11111 11111111 11111111 11111111 11111111 11111111 11111111\n // 0 <= v < 9007199254740992\n v = ( ( a[i] & 31 ) * 0x1000000000000 ) + ( a[i + 1] * 0x10000000000 ) +\n ( a[i + 2] * 0x100000000 ) + ( a[i + 3] * 0x1000000 ) +\n ( a[i + 4] << 16 ) + ( a[i + 5] << 8 ) + a[i + 6];\n\n if ( v >= 9e15 ) {\n crypto.randomBytes(7).copy( a, i );\n } else {\n\n // 0 <= (v % 1e14) <= 99999999999999\n c.push( v % 1e14 );\n i += 7;\n }\n }\n i = k / 7;\n } else if (ERRORS) {\n raise( 14, 'crypto unavailable', crypto );\n }\n }\n\n // Use Math.random: CRYPTO is false or crypto is unavailable and ERRORS is false.\n if (!i) {\n\n for ( ; i < k; ) {\n v = random53bitInt();\n if ( v < 9e15 ) c[i++] = v % 1e14;\n }\n }\n\n k = c[--i];\n dp %= LOG_BASE;\n\n // Convert trailing digits to zeros according to dp.\n if ( k && dp ) {\n v = POWS_TEN[LOG_BASE - dp];\n c[i] = mathfloor( k / v ) * v;\n }\n\n // Remove trailing elements which are zero.\n for ( ; c[i] === 0; c.pop(), i-- );\n\n // Zero?\n if ( i < 0 ) {\n c = [ e = 0 ];\n } else {\n\n // Remove leading elements which are zero and adjust exponent accordingly.\n for ( e = -1 ; c[0] === 0; c.shift(), e -= LOG_BASE);\n\n // Count the digits of the first element of c to determine leading zeros, and...\n for ( i = 1, v = c[0]; v >= 10; v /= 10, i++);\n\n // adjust the exponent accordingly.\n if ( i < LOG_BASE ) e -= LOG_BASE - i;\n }\n\n rand.e = e;\n rand.c = c;\n return rand;\n };\n })();\n\n\n // PRIVATE FUNCTIONS\n\n\n // Convert a numeric string of baseIn to a numeric string of baseOut.\n function convertBase( str, baseOut, baseIn, sign ) {\n var d, e, k, r, x, xc, y,\n i = str.indexOf( '.' ),\n dp = DECIMAL_PLACES,\n rm = ROUNDING_MODE;\n\n if ( baseIn < 37 ) str = str.toLowerCase();\n\n // Non-integer.\n if ( i >= 0 ) {\n k = POW_PRECISION;\n\n // Unlimited precision.\n POW_PRECISION = 0;\n str = str.replace( '.', '' );\n y = new BigNumber(baseIn);\n x = y.pow( str.length - i );\n POW_PRECISION = k;\n\n // Convert str as if an integer, then restore the fraction part by dividing the\n // result by its base raised to a power.\n y.c = toBaseOut( toFixedPoint( coeffToString( x.c ), x.e ), 10, baseOut );\n y.e = y.c.length;\n }\n\n // Convert the number as integer.\n xc = toBaseOut( str, baseIn, baseOut );\n e = k = xc.length;\n\n // Remove trailing zeros.\n for ( ; xc[--k] == 0; xc.pop() );\n if ( !xc[0] ) return '0';\n\n if ( i < 0 ) {\n --e;\n } else {\n x.c = xc;\n x.e = e;\n\n // sign is needed for correct rounding.\n x.s = sign;\n x = div( x, y, dp, rm, baseOut );\n xc = x.c;\n r = x.r;\n e = x.e;\n }\n\n d = e + dp + 1;\n\n // The rounding digit, i.e. the digit to the right of the digit that may be rounded up.\n i = xc[d];\n k = baseOut / 2;\n r = r || d < 0 || xc[d + 1] != null;\n\n r = rm < 4 ? ( i != null || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) )\n : i > k || i == k &&( rm == 4 || r || rm == 6 && xc[d - 1] & 1 ||\n rm == ( x.s < 0 ? 8 : 7 ) );\n\n if ( d < 1 || !xc[0] ) {\n\n // 1^-dp or 0.\n str = r ? toFixedPoint( '1', -dp ) : '0';\n } else {\n xc.length = d;\n\n if (r) {\n\n // Rounding up may mean the previous digit has to be rounded up and so on.\n for ( --baseOut; ++xc[--d] > baseOut; ) {\n xc[d] = 0;\n\n if ( !d ) {\n ++e;\n xc.unshift(1);\n }\n }\n }\n\n // Determine trailing zeros.\n for ( k = xc.length; !xc[--k]; );\n\n // E.g. [4, 11, 15] becomes 4bf.\n for ( i = 0, str = ''; i <= k; str += ALPHABET.charAt( xc[i++] ) );\n str = toFixedPoint( str, e );\n }\n\n // The caller will add the sign.\n return str;\n }\n\n\n // Perform division in the specified base. Called by div and convertBase.\n div = (function () {\n\n // Assume non-zero x and k.\n function multiply( x, k, base ) {\n var m, temp, xlo, xhi,\n carry = 0,\n i = x.length,\n klo = k % SQRT_BASE,\n khi = k / SQRT_BASE | 0;\n\n for ( x = x.slice(); i--; ) {\n xlo = x[i] % SQRT_BASE;\n xhi = x[i] / SQRT_BASE | 0;\n m = khi * xlo + xhi * klo;\n temp = klo * xlo + ( ( m % SQRT_BASE ) * SQRT_BASE ) + carry;\n carry = ( temp / base | 0 ) + ( m / SQRT_BASE | 0 ) + khi * xhi;\n x[i] = temp % base;\n }\n\n if (carry) x.unshift(carry);\n\n return x;\n }\n\n function compare( a, b, aL, bL ) {\n var i, cmp;\n\n if ( aL != bL ) {\n cmp = aL > bL ? 1 : -1;\n } else {\n\n for ( i = cmp = 0; i < aL; i++ ) {\n\n if ( a[i] != b[i] ) {\n cmp = a[i] > b[i] ? 1 : -1;\n break;\n }\n }\n }\n return cmp;\n }\n\n function subtract( a, b, aL, base ) {\n var i = 0;\n\n // Subtract b from a.\n for ( ; aL--; ) {\n a[aL] -= i;\n i = a[aL] < b[aL] ? 1 : 0;\n a[aL] = i * base + a[aL] - b[aL];\n }\n\n // Remove leading zeros.\n for ( ; !a[0] && a.length > 1; a.shift() );\n }\n\n // x: dividend, y: divisor.\n return function ( x, y, dp, rm, base ) {\n var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0,\n yL, yz,\n s = x.s == y.s ? 1 : -1,\n xc = x.c,\n yc = y.c;\n\n // Either NaN, Infinity or 0?\n if ( !xc || !xc[0] || !yc || !yc[0] ) {\n\n return new BigNumber(\n\n // Return NaN if either NaN, or both Infinity or 0.\n !x.s || !y.s || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN :\n\n // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0.\n xc && xc[0] == 0 || !yc ? s * 0 : s / 0\n );\n }\n\n q = new BigNumber(s);\n qc = q.c = [];\n e = x.e - y.e;\n s = dp + e + 1;\n\n if ( !base ) {\n base = BASE;\n e = bitFloor( x.e / LOG_BASE ) - bitFloor( y.e / LOG_BASE );\n s = s / LOG_BASE | 0;\n }\n\n // Result exponent may be one less then the current value of e.\n // The coefficients of the BigNumbers from convertBase may have trailing zeros.\n for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ );\n if ( yc[i] > ( xc[i] || 0 ) ) e--;\n\n if ( s < 0 ) {\n qc.push(1);\n more = true;\n } else {\n xL = xc.length;\n yL = yc.length;\n i = 0;\n s += 2;\n\n // Normalise xc and yc so highest order digit of yc is >= base / 2.\n\n n = mathfloor( base / ( yc[0] + 1 ) );\n\n // Not necessary, but to handle odd bases where yc[0] == ( base / 2 ) - 1.\n // if ( n > 1 || n++ == 1 && yc[0] < base / 2 ) {\n if ( n > 1 ) {\n yc = multiply( yc, n, base );\n xc = multiply( xc, n, base );\n yL = yc.length;\n xL = xc.length;\n }\n\n xi = yL;\n rem = xc.slice( 0, yL );\n remL = rem.length;\n\n // Add zeros to make remainder as long as divisor.\n for ( ; remL < yL; rem[remL++] = 0 );\n yz = yc.slice();\n yz.unshift(0);\n yc0 = yc[0];\n if ( yc[1] >= base / 2 ) yc0++;\n // Not necessary, but to prevent trial digit n > base, when using base 3.\n // else if ( base == 3 && yc0 == 1 ) yc0 = 1 + 1e-15;\n\n do {\n n = 0;\n\n // Compare divisor and remainder.\n cmp = compare( yc, rem, yL, remL );\n\n // If divisor < remainder.\n if ( cmp < 0 ) {\n\n // Calculate trial digit, n.\n\n rem0 = rem[0];\n if ( yL != remL ) rem0 = rem0 * base + ( rem[1] || 0 );\n\n // n is how many times the divisor goes into the current remainder.\n n = mathfloor( rem0 / yc0 );\n\n // Algorithm:\n // 1. product = divisor * trial digit (n)\n // 2. if product > remainder: product -= divisor, n--\n // 3. remainder -= product\n // 4. if product was < remainder at 2:\n // 5. compare new remainder and divisor\n // 6. If remainder > divisor: remainder -= divisor, n++\n\n if ( n > 1 ) {\n\n // n may be > base only when base is 3.\n if (n >= base) n = base - 1;\n\n // product = divisor * trial digit.\n prod = multiply( yc, n, base );\n prodL = prod.length;\n remL = rem.length;\n\n // Compare product and remainder.\n // If product > remainder.\n // Trial digit n too high.\n // n is 1 too high about 5% of the time, and is not known to have\n // ever been more than 1 too high.\n while ( compare( prod, rem, prodL, remL ) == 1 ) {\n n--;\n\n // Subtract divisor from product.\n subtract( prod, yL < prodL ? yz : yc, prodL, base );\n prodL = prod.length;\n cmp = 1;\n }\n } else {\n\n // n is 0 or 1, cmp is -1.\n // If n is 0, there is no need to compare yc and rem again below,\n // so change cmp to 1 to avoid it.\n // If n is 1, leave cmp as -1, so yc and rem are compared again.\n if ( n == 0 ) {\n\n // divisor < remainder, so n must be at least 1.\n cmp = n = 1;\n }\n\n // product = divisor\n prod = yc.slice();\n prodL = prod.length;\n }\n\n if ( prodL < remL ) prod.unshift(0);\n\n // Subtract product from remainder.\n subtract( rem, prod, remL, base );\n remL = rem.length;\n\n // If product was < remainder.\n if ( cmp == -1 ) {\n\n // Compare divisor and new remainder.\n // If divisor < new remainder, subtract divisor from remainder.\n // Trial digit n too low.\n // n is 1 too low about 5% of the time, and very rarely 2 too low.\n while ( compare( yc, rem, yL, remL ) < 1 ) {\n n++;\n\n // Subtract divisor from remainder.\n subtract( rem, yL < remL ? yz : yc, remL, base );\n remL = rem.length;\n }\n }\n } else if ( cmp === 0 ) {\n n++;\n rem = [0];\n } // else cmp === 1 and n will be 0\n\n // Add the next digit, n, to the result array.\n qc[i++] = n;\n\n // Update the remainder.\n if ( rem[0] ) {\n rem[remL++] = xc[xi] || 0;\n } else {\n rem = [ xc[xi] ];\n remL = 1;\n }\n } while ( ( xi++ < xL || rem[0] != null ) && s-- );\n\n more = rem[0] != null;\n\n // Leading zero?\n if ( !qc[0] ) qc.shift();\n }\n\n if ( base == BASE ) {\n\n // To calculate q.e, first get the number of digits of qc[0].\n for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ );\n round( q, dp + ( q.e = i + e * LOG_BASE - 1 ) + 1, rm, more );\n\n // Caller is convertBase.\n } else {\n q.e = e;\n q.r = +more;\n }\n\n return q;\n };\n })();\n\n\n /*\n * Return a string representing the value of BigNumber n in fixed-point or exponential\n * notation rounded to the specified decimal places or significant digits.\n *\n * n is a BigNumber.\n * i is the index of the last digit required (i.e. the digit that may be rounded up).\n * rm is the rounding mode.\n * caller is caller id: toExponential 19, toFixed 20, toFormat 21, toPrecision 24.\n */\n function format( n, i, rm, caller ) {\n var c0, e, ne, len, str;\n\n rm = rm != null && isValidInt( rm, 0, 8, caller, roundingMode )\n ? rm | 0 : ROUNDING_MODE;\n\n if ( !n.c ) return n.toString();\n c0 = n.c[0];\n ne = n.e;\n\n if ( i == null ) {\n str = coeffToString( n.c );\n str = caller == 19 || caller == 24 && ne <= TO_EXP_NEG\n ? toExponential( str, ne )\n : toFixedPoint( str, ne );\n } else {\n n = round( new BigNumber(n), i, rm );\n\n // n.e may have changed if the value was rounded up.\n e = n.e;\n\n str = coeffToString( n.c );\n len = str.length;\n\n // toPrecision returns exponential notation if the number of significant digits\n // specified is less than the number of digits necessary to represent the integer\n // part of the value in fixed-point notation.\n\n // Exponential notation.\n if ( caller == 19 || caller == 24 && ( i <= e || e <= TO_EXP_NEG ) ) {\n\n // Append zeros?\n for ( ; len < i; str += '0', len++ );\n str = toExponential( str, e );\n\n // Fixed-point notation.\n } else {\n i -= ne;\n str = toFixedPoint( str, e );\n\n // Append zeros?\n if ( e + 1 > len ) {\n if ( --i > 0 ) for ( str += '.'; i--; str += '0' );\n } else {\n i += e - len;\n if ( i > 0 ) {\n if ( e + 1 == len ) str += '.';\n for ( ; i--; str += '0' );\n }\n }\n }\n }\n\n return n.s < 0 && c0 ? '-' + str : str;\n }\n\n\n // Handle BigNumber.max and BigNumber.min.\n function maxOrMin( args, method ) {\n var m, n,\n i = 0;\n\n if ( isArray( args[0] ) ) args = args[0];\n m = new BigNumber( args[0] );\n\n for ( ; ++i < args.length; ) {\n n = new BigNumber( args[i] );\n\n // If any number is NaN, return NaN.\n if ( !n.s ) {\n m = n;\n break;\n } else if ( method.call( m, n ) ) {\n m = n;\n }\n }\n\n return m;\n }\n\n\n /*\n * Return true if n is an integer in range, otherwise throw.\n * Use for argument validation when ERRORS is true.\n */\n function intValidatorWithErrors( n, min, max, caller, name ) {\n if ( n < min || n > max || n != truncate(n) ) {\n raise( caller, ( name || 'decimal places' ) +\n ( n < min || n > max ? ' out of range' : ' not an integer' ), n );\n }\n\n return true;\n }\n\n\n /*\n * Strip trailing zeros, calculate base 10 exponent and check against MIN_EXP and MAX_EXP.\n * Called by minus, plus and times.\n */\n function normalise( n, c, e ) {\n var i = 1,\n j = c.length;\n\n // Remove trailing zeros.\n for ( ; !c[--j]; c.pop() );\n\n // Calculate the base 10 exponent. First get the number of digits of c[0].\n for ( j = c[0]; j >= 10; j /= 10, i++ );\n\n // Overflow?\n if ( ( e = i + e * LOG_BASE - 1 ) > MAX_EXP ) {\n\n // Infinity.\n n.c = n.e = null;\n\n // Underflow?\n } else if ( e < MIN_EXP ) {\n\n // Zero.\n n.c = [ n.e = 0 ];\n } else {\n n.e = e;\n n.c = c;\n }\n\n return n;\n }\n\n\n // Handle values that fail the validity test in BigNumber.\n parseNumeric = (function () {\n var basePrefix = /^(-?)0([xbo])/i,\n dotAfter = /^([^.]+)\\.$/,\n dotBefore = /^\\.([^.]+)$/,\n isInfinityOrNaN = /^-?(Infinity|NaN)$/,\n whitespaceOrPlus = /^\\s*\\+|^\\s+|\\s+$/g;\n\n return function ( x, str, num, b ) {\n var base,\n s = num ? str : str.replace( whitespaceOrPlus, '' );\n\n // No exception on ±Infinity or NaN.\n if ( isInfinityOrNaN.test(s) ) {\n x.s = isNaN(s) ? null : s < 0 ? -1 : 1;\n } else {\n if ( !num ) {\n\n // basePrefix = /^(-?)0([xbo])(?=\\w[\\w.]*$)/i\n s = s.replace( basePrefix, function ( m, p1, p2 ) {\n base = ( p2 = p2.toLowerCase() ) == 'x' ? 16 : p2 == 'b' ? 2 : 8;\n return !b || b == base ? p1 : m;\n });\n\n if (b) {\n base = b;\n\n // E.g. '1.' to '1', '.1' to '0.1'\n s = s.replace( dotAfter, '$1' ).replace( dotBefore, '0.$1' );\n }\n\n if ( str != s ) return new BigNumber( s, base );\n }\n\n // 'new BigNumber() not a number: {n}'\n // 'new BigNumber() not a base {b} number: {n}'\n if (ERRORS) raise( id, 'not a' + ( b ? ' base ' + b : '' ) + ' number', str );\n x.s = null;\n }\n\n x.c = x.e = null;\n id = 0;\n }\n })();\n\n\n // Throw a BigNumber Error.\n function raise( caller, msg, val ) {\n var error = new Error( [\n 'new BigNumber', // 0\n 'cmp', // 1\n 'config', // 2\n 'div', // 3\n 'divToInt', // 4\n 'eq', // 5\n 'gt', // 6\n 'gte', // 7\n 'lt', // 8\n 'lte', // 9\n 'minus', // 10\n 'mod', // 11\n 'plus', // 12\n 'precision', // 13\n 'random', // 14\n 'round', // 15\n 'shift', // 16\n 'times', // 17\n 'toDigits', // 18\n 'toExponential', // 19\n 'toFixed', // 20\n 'toFormat', // 21\n 'toFraction', // 22\n 'pow', // 23\n 'toPrecision', // 24\n 'toString', // 25\n 'BigNumber' // 26\n ][caller] + '() ' + msg + ': ' + val );\n\n error.name = 'BigNumber Error';\n id = 0;\n throw error;\n }\n\n\n /*\n * Round x to sd significant digits using rounding mode rm. Check for over/under-flow.\n * If r is truthy, it is known that there are more digits after the rounding digit.\n */\n function round( x, sd, rm, r ) {\n var d, i, j, k, n, ni, rd,\n xc = x.c,\n pows10 = POWS_TEN;\n\n // if x is not Infinity or NaN...\n if (xc) {\n\n // rd is the rounding digit, i.e. the digit after the digit that may be rounded up.\n // n is a base 1e14 number, the value of the element of array x.c containing rd.\n // ni is the index of n within x.c.\n // d is the number of digits of n.\n // i is the index of rd within n including leading zeros.\n // j is the actual index of rd within n (if < 0, rd is a leading zero).\n out: {\n\n // Get the number of digits of the first element of xc.\n for ( d = 1, k = xc[0]; k >= 10; k /= 10, d++ );\n i = sd - d;\n\n // If the rounding digit is in the first element of xc...\n if ( i < 0 ) {\n i += LOG_BASE;\n j = sd;\n n = xc[ ni = 0 ];\n\n // Get the rounding digit at index j of n.\n rd = n / pows10[ d - j - 1 ] % 10 | 0;\n } else {\n ni = mathceil( ( i + 1 ) / LOG_BASE );\n\n if ( ni >= xc.length ) {\n\n if (r) {\n\n // Needed by sqrt.\n for ( ; xc.length <= ni; xc.push(0) );\n n = rd = 0;\n d = 1;\n i %= LOG_BASE;\n j = i - LOG_BASE + 1;\n } else {\n break out;\n }\n } else {\n n = k = xc[ni];\n\n // Get the number of digits of n.\n for ( d = 1; k >= 10; k /= 10, d++ );\n\n // Get the index of rd within n.\n i %= LOG_BASE;\n\n // Get the index of rd within n, adjusted for leading zeros.\n // The number of leading zeros of n is given by LOG_BASE - d.\n j = i - LOG_BASE + d;\n\n // Get the rounding digit at index j of n.\n rd = j < 0 ? 0 : n / pows10[ d - j - 1 ] % 10 | 0;\n }\n }\n\n r = r || sd < 0 ||\n\n // Are there any non-zero digits after the rounding digit?\n // The expression n % pows10[ d - j - 1 ] returns all digits of n to the right\n // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714.\n xc[ni + 1] != null || ( j < 0 ? n : n % pows10[ d - j - 1 ] );\n\n r = rm < 4\n ? ( rd || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) )\n : rd > 5 || rd == 5 && ( rm == 4 || r || rm == 6 &&\n\n // Check whether the digit to the left of the rounding digit is odd.\n ( ( i > 0 ? j > 0 ? n / pows10[ d - j ] : 0 : xc[ni - 1] ) % 10 ) & 1 ||\n rm == ( x.s < 0 ? 8 : 7 ) );\n\n if ( sd < 1 || !xc[0] ) {\n xc.length = 0;\n\n if (r) {\n\n // Convert sd to decimal places.\n sd -= x.e + 1;\n\n // 1, 0.1, 0.01, 0.001, 0.0001 etc.\n xc[0] = pows10[ sd % LOG_BASE ];\n x.e = -sd || 0;\n } else {\n\n // Zero.\n xc[0] = x.e = 0;\n }\n\n return x;\n }\n\n // Remove excess digits.\n if ( i == 0 ) {\n xc.length = ni;\n k = 1;\n ni--;\n } else {\n xc.length = ni + 1;\n k = pows10[ LOG_BASE - i ];\n\n // E.g. 56700 becomes 56000 if 7 is the rounding digit.\n // j > 0 means i > number of leading zeros of n.\n xc[ni] = j > 0 ? mathfloor( n / pows10[ d - j ] % pows10[j] ) * k : 0;\n }\n\n // Round up?\n if (r) {\n\n for ( ; ; ) {\n\n // If the digit to be rounded up is in the first element of xc...\n if ( ni == 0 ) {\n\n // i will be the length of xc[0] before k is added.\n for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ );\n j = xc[0] += k;\n for ( k = 1; j >= 10; j /= 10, k++ );\n\n // if i != k the length has increased.\n if ( i != k ) {\n x.e++;\n if ( xc[0] == BASE ) xc[0] = 1;\n }\n\n break;\n } else {\n xc[ni] += k;\n if ( xc[ni] != BASE ) break;\n xc[ni--] = 0;\n k = 1;\n }\n }\n }\n\n // Remove trailing zeros.\n for ( i = xc.length; xc[--i] === 0; xc.pop() );\n }\n\n // Overflow? Infinity.\n if ( x.e > MAX_EXP ) {\n x.c = x.e = null;\n\n // Underflow? Zero.\n } else if ( x.e < MIN_EXP ) {\n x.c = [ x.e = 0 ];\n }\n }\n\n return x;\n }\n\n\n // PROTOTYPE/INSTANCE METHODS\n\n\n /*\n * Return a new BigNumber whose value is the absolute value of this BigNumber.\n */\n P.absoluteValue = P.abs = function () {\n var x = new BigNumber(this);\n if ( x.s < 0 ) x.s = 1;\n return x;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole\n * number in the direction of Infinity.\n */\n P.ceil = function () {\n return round( new BigNumber(this), this.e + 1, 2 );\n };\n\n\n /*\n * Return\n * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b),\n * -1 if the value of this BigNumber is less than the value of BigNumber(y, b),\n * 0 if they have the same value,\n * or null if the value of either is NaN.\n */\n P.comparedTo = P.cmp = function ( y, b ) {\n id = 1;\n return compare( this, new BigNumber( y, b ) );\n };\n\n\n /*\n * Return the number of decimal places of the value of this BigNumber, or null if the value\n * of this BigNumber is ±Infinity or NaN.\n */\n P.decimalPlaces = P.dp = function () {\n var n, v,\n c = this.c;\n\n if ( !c ) return null;\n n = ( ( v = c.length - 1 ) - bitFloor( this.e / LOG_BASE ) ) * LOG_BASE;\n\n // Subtract the number of trailing zeros of the last number.\n if ( v = c[v] ) for ( ; v % 10 == 0; v /= 10, n-- );\n if ( n < 0 ) n = 0;\n\n return n;\n };\n\n\n /*\n * n / 0 = I\n * n / N = N\n * n / I = 0\n * 0 / n = 0\n * 0 / 0 = N\n * 0 / N = N\n * 0 / I = 0\n * N / n = N\n * N / 0 = N\n * N / N = N\n * N / I = N\n * I / n = I\n * I / 0 = I\n * I / N = N\n * I / I = N\n *\n * Return a new BigNumber whose value is the value of this BigNumber divided by the value of\n * BigNumber(y, b), rounded according to DECIMAL_PLACES and ROUNDING_MODE.\n */\n P.dividedBy = P.div = function ( y, b ) {\n id = 3;\n return div( this, new BigNumber( y, b ), DECIMAL_PLACES, ROUNDING_MODE );\n };\n\n\n /*\n * Return a new BigNumber whose value is the integer part of dividing the value of this\n * BigNumber by the value of BigNumber(y, b).\n */\n P.dividedToIntegerBy = P.divToInt = function ( y, b ) {\n id = 4;\n return div( this, new BigNumber( y, b ), 0, 1 );\n };\n\n\n /*\n * Return true if the value of this BigNumber is equal to the value of BigNumber(y, b),\n * otherwise returns false.\n */\n P.equals = P.eq = function ( y, b ) {\n id = 5;\n return compare( this, new BigNumber( y, b ) ) === 0;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole\n * number in the direction of -Infinity.\n */\n P.floor = function () {\n return round( new BigNumber(this), this.e + 1, 3 );\n };\n\n\n /*\n * Return true if the value of this BigNumber is greater than the value of BigNumber(y, b),\n * otherwise returns false.\n */\n P.greaterThan = P.gt = function ( y, b ) {\n id = 6;\n return compare( this, new BigNumber( y, b ) ) > 0;\n };\n\n\n /*\n * Return true if the value of this BigNumber is greater than or equal to the value of\n * BigNumber(y, b), otherwise returns false.\n */\n P.greaterThanOrEqualTo = P.gte = function ( y, b ) {\n id = 7;\n return ( b = compare( this, new BigNumber( y, b ) ) ) === 1 || b === 0;\n\n };\n\n\n /*\n * Return true if the value of this BigNumber is a finite number, otherwise returns false.\n */\n P.isFinite = function () {\n return !!this.c;\n };\n\n\n /*\n * Return true if the value of this BigNumber is an integer, otherwise return false.\n */\n P.isInteger = P.isInt = function () {\n return !!this.c && bitFloor( this.e / LOG_BASE ) > this.c.length - 2;\n };\n\n\n /*\n * Return true if the value of this BigNumber is NaN, otherwise returns false.\n */\n P.isNaN = function () {\n return !this.s;\n };\n\n\n /*\n * Return true if the value of this BigNumber is negative, otherwise returns false.\n */\n P.isNegative = P.isNeg = function () {\n return this.s < 0;\n };\n\n\n /*\n * Return true if the value of this BigNumber is 0 or -0, otherwise returns false.\n */\n P.isZero = function () {\n return !!this.c && this.c[0] == 0;\n };\n\n\n /*\n * Return true if the value of this BigNumber is less than the value of BigNumber(y, b),\n * otherwise returns false.\n */\n P.lessThan = P.lt = function ( y, b ) {\n id = 8;\n return compare( this, new BigNumber( y, b ) ) < 0;\n };\n\n\n /*\n * Return true if the value of this BigNumber is less than or equal to the value of\n * BigNumber(y, b), otherwise returns false.\n */\n P.lessThanOrEqualTo = P.lte = function ( y, b ) {\n id = 9;\n return ( b = compare( this, new BigNumber( y, b ) ) ) === -1 || b === 0;\n };\n\n\n /*\n * n - 0 = n\n * n - N = N\n * n - I = -I\n * 0 - n = -n\n * 0 - 0 = 0\n * 0 - N = N\n * 0 - I = -I\n * N - n = N\n * N - 0 = N\n * N - N = N\n * N - I = N\n * I - n = I\n * I - 0 = I\n * I - N = N\n * I - I = N\n *\n * Return a new BigNumber whose value is the value of this BigNumber minus the value of\n * BigNumber(y, b).\n */\n P.minus = P.sub = function ( y, b ) {\n var i, j, t, xLTy,\n x = this,\n a = x.s;\n\n id = 10;\n y = new BigNumber( y, b );\n b = y.s;\n\n // Either NaN?\n if ( !a || !b ) return new BigNumber(NaN);\n\n // Signs differ?\n if ( a != b ) {\n y.s = -b;\n return x.plus(y);\n }\n\n var xe = x.e / LOG_BASE,\n ye = y.e / LOG_BASE,\n xc = x.c,\n yc = y.c;\n\n if ( !xe || !ye ) {\n\n // Either Infinity?\n if ( !xc || !yc ) return xc ? ( y.s = -b, y ) : new BigNumber( yc ? x : NaN );\n\n // Either zero?\n if ( !xc[0] || !yc[0] ) {\n\n // Return y if y is non-zero, x if x is non-zero, or zero if both are zero.\n return yc[0] ? ( y.s = -b, y ) : new BigNumber( xc[0] ? x :\n\n // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity\n ROUNDING_MODE == 3 ? -0 : 0 );\n }\n }\n\n xe = bitFloor(xe);\n ye = bitFloor(ye);\n xc = xc.slice();\n\n // Determine which is the bigger number.\n if ( a = xe - ye ) {\n\n if ( xLTy = a < 0 ) {\n a = -a;\n t = xc;\n } else {\n ye = xe;\n t = yc;\n }\n\n t.reverse();\n\n // Prepend zeros to equalise exponents.\n for ( b = a; b--; t.push(0) );\n t.reverse();\n } else {\n\n // Exponents equal. Check digit by digit.\n j = ( xLTy = ( a = xc.length ) < ( b = yc.length ) ) ? a : b;\n\n for ( a = b = 0; b < j; b++ ) {\n\n if ( xc[b] != yc[b] ) {\n xLTy = xc[b] < yc[b];\n break;\n }\n }\n }\n\n // x < y? Point xc to the array of the bigger number.\n if (xLTy) t = xc, xc = yc, yc = t, y.s = -y.s;\n\n b = ( j = yc.length ) - ( i = xc.length );\n\n // Append zeros to xc if shorter.\n // No need to add zeros to yc if shorter as subtract only needs to start at yc.length.\n if ( b > 0 ) for ( ; b--; xc[i++] = 0 );\n b = BASE - 1;\n\n // Subtract yc from xc.\n for ( ; j > a; ) {\n\n if ( xc[--j] < yc[j] ) {\n for ( i = j; i && !xc[--i]; xc[i] = b );\n --xc[i];\n xc[j] += BASE;\n }\n\n xc[j] -= yc[j];\n }\n\n // Remove leading zeros and adjust exponent accordingly.\n for ( ; xc[0] == 0; xc.shift(), --ye );\n\n // Zero?\n if ( !xc[0] ) {\n\n // Following IEEE 754 (2008) 6.3,\n // n - n = +0 but n - n = -0 when rounding towards -Infinity.\n y.s = ROUNDING_MODE == 3 ? -1 : 1;\n y.c = [ y.e = 0 ];\n return y;\n }\n\n // No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity\n // for finite x and y.\n return normalise( y, xc, ye );\n };\n\n\n /*\n * n % 0 = N\n * n % N = N\n * n % I = n\n * 0 % n = 0\n * -0 % n = -0\n * 0 % 0 = N\n * 0 % N = N\n * 0 % I = 0\n * N % n = N\n * N % 0 = N\n * N % N = N\n * N % I = N\n * I % n = N\n * I % 0 = N\n * I % N = N\n * I % I = N\n *\n * Return a new BigNumber whose value is the value of this BigNumber modulo the value of\n * BigNumber(y, b). The result depends on the value of MODULO_MODE.\n */\n P.modulo = P.mod = function ( y, b ) {\n var q, s,\n x = this;\n\n id = 11;\n y = new BigNumber( y, b );\n\n // Return NaN if x is Infinity or NaN, or y is NaN or zero.\n if ( !x.c || !y.s || y.c && !y.c[0] ) {\n return new BigNumber(NaN);\n\n // Return x if y is Infinity or x is zero.\n } else if ( !y.c || x.c && !x.c[0] ) {\n return new BigNumber(x);\n }\n\n if ( MODULO_MODE == 9 ) {\n\n // Euclidian division: q = sign(y) * floor(x / abs(y))\n // r = x - qy where 0 <= r < abs(y)\n s = y.s;\n y.s = 1;\n q = div( x, y, 0, 3 );\n y.s = s;\n q.s *= s;\n } else {\n q = div( x, y, 0, MODULO_MODE );\n }\n\n return x.minus( q.times(y) );\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber negated,\n * i.e. multiplied by -1.\n */\n P.negated = P.neg = function () {\n var x = new BigNumber(this);\n x.s = -x.s || null;\n return x;\n };\n\n\n /*\n * n + 0 = n\n * n + N = N\n * n + I = I\n * 0 + n = n\n * 0 + 0 = 0\n * 0 + N = N\n * 0 + I = I\n * N + n = N\n * N + 0 = N\n * N + N = N\n * N + I = N\n * I + n = I\n * I + 0 = I\n * I + N = N\n * I + I = I\n *\n * Return a new BigNumber whose value is the value of this BigNumber plus the value of\n * BigNumber(y, b).\n */\n P.plus = P.add = function ( y, b ) {\n var t,\n x = this,\n a = x.s;\n\n id = 12;\n y = new BigNumber( y, b );\n b = y.s;\n\n // Either NaN?\n if ( !a || !b ) return new BigNumber(NaN);\n\n // Signs differ?\n if ( a != b ) {\n y.s = -b;\n return x.minus(y);\n }\n\n var xe = x.e / LOG_BASE,\n ye = y.e / LOG_BASE,\n xc = x.c,\n yc = y.c;\n\n if ( !xe || !ye ) {\n\n // Return ±Infinity if either ±Infinity.\n if ( !xc || !yc ) return new BigNumber( a / 0 );\n\n // Either zero?\n // Return y if y is non-zero, x if x is non-zero, or zero if both are zero.\n if ( !xc[0] || !yc[0] ) return yc[0] ? y : new BigNumber( xc[0] ? x : a * 0 );\n }\n\n xe = bitFloor(xe);\n ye = bitFloor(ye);\n xc = xc.slice();\n\n // Prepend zeros to equalise exponents. Faster to use reverse then do unshifts.\n if ( a = xe - ye ) {\n if ( a > 0 ) {\n ye = xe;\n t = yc;\n } else {\n a = -a;\n t = xc;\n }\n\n t.reverse();\n for ( ; a--; t.push(0) );\n t.reverse();\n }\n\n a = xc.length;\n b = yc.length;\n\n // Point xc to the longer array, and b to the shorter length.\n if ( a - b < 0 ) t = yc, yc = xc, xc = t, b = a;\n\n // Only start adding at yc.length - 1 as the further digits of xc can be ignored.\n for ( a = 0; b; ) {\n a = ( xc[--b] = xc[b] + yc[b] + a ) / BASE | 0;\n xc[b] %= BASE;\n }\n\n if (a) {\n xc.unshift(a);\n ++ye;\n }\n\n // No need to check for zero, as +x + +y != 0 && -x + -y != 0\n // ye = MAX_EXP + 1 possible\n return normalise( y, xc, ye );\n };\n\n\n /*\n * Return the number of significant digits of the value of this BigNumber.\n *\n * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0.\n */\n P.precision = P.sd = function (z) {\n var n, v,\n x = this,\n c = x.c;\n\n // 'precision() argument not a boolean or binary digit: {z}'\n if ( z != null && z !== !!z && z !== 1 && z !== 0 ) {\n if (ERRORS) raise( 13, 'argument' + notBool, z );\n if ( z != !!z ) z = null;\n }\n\n if ( !c ) return null;\n v = c.length - 1;\n n = v * LOG_BASE + 1;\n\n if ( v = c[v] ) {\n\n // Subtract the number of trailing zeros of the last element.\n for ( ; v % 10 == 0; v /= 10, n-- );\n\n // Add the number of digits of the first element.\n for ( v = c[0]; v >= 10; v /= 10, n++ );\n }\n\n if ( z && x.e + 1 > n ) n = x.e + 1;\n\n return n;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of\n * dp decimal places using rounding mode rm, or to 0 and ROUNDING_MODE respectively if\n * omitted.\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'round() decimal places out of range: {dp}'\n * 'round() decimal places not an integer: {dp}'\n * 'round() rounding mode not an integer: {rm}'\n * 'round() rounding mode out of range: {rm}'\n */\n P.round = function ( dp, rm ) {\n var n = new BigNumber(this);\n\n if ( dp == null || isValidInt( dp, 0, MAX, 15 ) ) {\n round( n, ~~dp + this.e + 1, rm == null ||\n !isValidInt( rm, 0, 8, 15, roundingMode ) ? ROUNDING_MODE : rm | 0 );\n }\n\n return n;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber shifted by k places\n * (powers of 10). Shift to the right if n > 0, and to the left if n < 0.\n *\n * k {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive.\n *\n * If k is out of range and ERRORS is false, the result will be ±0 if k < 0, or ±Infinity\n * otherwise.\n *\n * 'shift() argument not an integer: {k}'\n * 'shift() argument out of range: {k}'\n */\n P.shift = function (k) {\n var n = this;\n return isValidInt( k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 16, 'argument' )\n\n // k < 1e+21, or truncate(k) will produce exponential notation.\n ? n.times( '1e' + truncate(k) )\n : new BigNumber( n.c && n.c[0] && ( k < -MAX_SAFE_INTEGER || k > MAX_SAFE_INTEGER )\n ? n.s * ( k < 0 ? 0 : 1 / 0 )\n : n );\n };\n\n\n /*\n * sqrt(-n) = N\n * sqrt( N) = N\n * sqrt(-I) = N\n * sqrt( I) = I\n * sqrt( 0) = 0\n * sqrt(-0) = -0\n *\n * Return a new BigNumber whose value is the square root of the value of this BigNumber,\n * rounded according to DECIMAL_PLACES and ROUNDING_MODE.\n */\n P.squareRoot = P.sqrt = function () {\n var m, n, r, rep, t,\n x = this,\n c = x.c,\n s = x.s,\n e = x.e,\n dp = DECIMAL_PLACES + 4,\n half = new BigNumber('0.5');\n\n // Negative/NaN/Infinity/zero?\n if ( s !== 1 || !c || !c[0] ) {\n return new BigNumber( !s || s < 0 && ( !c || c[0] ) ? NaN : c ? x : 1 / 0 );\n }\n\n // Initial estimate.\n s = Math.sqrt( +x );\n\n // Math.sqrt underflow/overflow?\n // Pass x to Math.sqrt as integer, then adjust the exponent of the result.\n if ( s == 0 || s == 1 / 0 ) {\n n = coeffToString(c);\n if ( ( n.length + e ) % 2 == 0 ) n += '0';\n s = Math.sqrt(n);\n e = bitFloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 );\n\n if ( s == 1 / 0 ) {\n n = '1e' + e;\n } else {\n n = s.toExponential();\n n = n.slice( 0, n.indexOf('e') + 1 ) + e;\n }\n\n r = new BigNumber(n);\n } else {\n r = new BigNumber( s + '' );\n }\n\n // Check for zero.\n // r could be zero if MIN_EXP is changed after the this value was created.\n // This would cause a division by zero (x/t) and hence Infinity below, which would cause\n // coeffToString to throw.\n if ( r.c[0] ) {\n e = r.e;\n s = e + dp;\n if ( s < 3 ) s = 0;\n\n // Newton-Raphson iteration.\n for ( ; ; ) {\n t = r;\n r = half.times( t.plus( div( x, t, dp, 1 ) ) );\n\n if ( coeffToString( t.c ).slice( 0, s ) === ( n =\n coeffToString( r.c ) ).slice( 0, s ) ) {\n\n // The exponent of r may here be one less than the final result exponent,\n // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits\n // are indexed correctly.\n if ( r.e < e ) --s;\n n = n.slice( s - 3, s + 1 );\n\n // The 4th rounding digit may be in error by -1 so if the 4 rounding digits\n // are 9999 or 4999 (i.e. approaching a rounding boundary) continue the\n // iteration.\n if ( n == '9999' || !rep && n == '4999' ) {\n\n // On the first iteration only, check to see if rounding up gives the\n // exact result as the nines may infinitely repeat.\n if ( !rep ) {\n round( t, t.e + DECIMAL_PLACES + 2, 0 );\n\n if ( t.times(t).eq(x) ) {\n r = t;\n break;\n }\n }\n\n dp += 4;\n s += 4;\n rep = 1;\n } else {\n\n // If rounding digits are null, 0{0,4} or 50{0,3}, check for exact\n // result. If not, then there are further digits and m will be truthy.\n if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) {\n\n // Truncate to the first rounding digit.\n round( r, r.e + DECIMAL_PLACES + 2, 1 );\n m = !r.times(r).eq(x);\n }\n\n break;\n }\n }\n }\n }\n\n return round( r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m );\n };\n\n\n /*\n * n * 0 = 0\n * n * N = N\n * n * I = I\n * 0 * n = 0\n * 0 * 0 = 0\n * 0 * N = N\n * 0 * I = N\n * N * n = N\n * N * 0 = N\n * N * N = N\n * N * I = N\n * I * n = I\n * I * 0 = N\n * I * N = N\n * I * I = I\n *\n * Return a new BigNumber whose value is the value of this BigNumber times the value of\n * BigNumber(y, b).\n */\n P.times = P.mul = function ( y, b ) {\n var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc,\n base, sqrtBase,\n x = this,\n xc = x.c,\n yc = ( id = 17, y = new BigNumber( y, b ) ).c;\n\n // Either NaN, ±Infinity or ±0?\n if ( !xc || !yc || !xc[0] || !yc[0] ) {\n\n // Return NaN if either is NaN, or one is 0 and the other is Infinity.\n if ( !x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc ) {\n y.c = y.e = y.s = null;\n } else {\n y.s *= x.s;\n\n // Return ±Infinity if either is ±Infinity.\n if ( !xc || !yc ) {\n y.c = y.e = null;\n\n // Return ±0 if either is ±0.\n } else {\n y.c = [0];\n y.e = 0;\n }\n }\n\n return y;\n }\n\n e = bitFloor( x.e / LOG_BASE ) + bitFloor( y.e / LOG_BASE );\n y.s *= x.s;\n xcL = xc.length;\n ycL = yc.length;\n\n // Ensure xc points to longer array and xcL to its length.\n if ( xcL < ycL ) zc = xc, xc = yc, yc = zc, i = xcL, xcL = ycL, ycL = i;\n\n // Initialise the result array with zeros.\n for ( i = xcL + ycL, zc = []; i--; zc.push(0) );\n\n base = BASE;\n sqrtBase = SQRT_BASE;\n\n for ( i = ycL; --i >= 0; ) {\n c = 0;\n ylo = yc[i] % sqrtBase;\n yhi = yc[i] / sqrtBase | 0;\n\n for ( k = xcL, j = i + k; j > i; ) {\n xlo = xc[--k] % sqrtBase;\n xhi = xc[k] / sqrtBase | 0;\n m = yhi * xlo + xhi * ylo;\n xlo = ylo * xlo + ( ( m % sqrtBase ) * sqrtBase ) + zc[j] + c;\n c = ( xlo / base | 0 ) + ( m / sqrtBase | 0 ) + yhi * xhi;\n zc[j--] = xlo % base;\n }\n\n zc[j] = c;\n }\n\n if (c) {\n ++e;\n } else {\n zc.shift();\n }\n\n return normalise( y, zc, e );\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of\n * sd significant digits using rounding mode rm, or ROUNDING_MODE if rm is omitted.\n *\n * [sd] {number} Significant digits. Integer, 1 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toDigits() precision out of range: {sd}'\n * 'toDigits() precision not an integer: {sd}'\n * 'toDigits() rounding mode not an integer: {rm}'\n * 'toDigits() rounding mode out of range: {rm}'\n */\n P.toDigits = function ( sd, rm ) {\n var n = new BigNumber(this);\n sd = sd == null || !isValidInt( sd, 1, MAX, 18, 'precision' ) ? null : sd | 0;\n rm = rm == null || !isValidInt( rm, 0, 8, 18, roundingMode ) ? ROUNDING_MODE : rm | 0;\n return sd ? round( n, sd, rm ) : n;\n };\n\n\n /*\n * Return a string representing the value of this BigNumber in exponential notation and\n * rounded using ROUNDING_MODE to dp fixed decimal places.\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toExponential() decimal places not an integer: {dp}'\n * 'toExponential() decimal places out of range: {dp}'\n * 'toExponential() rounding mode not an integer: {rm}'\n * 'toExponential() rounding mode out of range: {rm}'\n */\n P.toExponential = function ( dp, rm ) {\n return format( this,\n dp != null && isValidInt( dp, 0, MAX, 19 ) ? ~~dp + 1 : null, rm, 19 );\n };\n\n\n /*\n * Return a string representing the value of this BigNumber in fixed-point notation rounding\n * to dp fixed decimal places using rounding mode rm, or ROUNDING_MODE if rm is omitted.\n *\n * Note: as with JavaScript's number type, (-0).toFixed(0) is '0',\n * but e.g. (-0.00001).toFixed(0) is '-0'.\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toFixed() decimal places not an integer: {dp}'\n * 'toFixed() decimal places out of range: {dp}'\n * 'toFixed() rounding mode not an integer: {rm}'\n * 'toFixed() rounding mode out of range: {rm}'\n */\n P.toFixed = function ( dp, rm ) {\n return format( this, dp != null && isValidInt( dp, 0, MAX, 20 )\n ? ~~dp + this.e + 1 : null, rm, 20 );\n };\n\n\n /*\n * Return a string representing the value of this BigNumber in fixed-point notation rounded\n * using rm or ROUNDING_MODE to dp decimal places, and formatted according to the properties\n * of the FORMAT object (see BigNumber.config).\n *\n * FORMAT = {\n * decimalSeparator : '.',\n * groupSeparator : ',',\n * groupSize : 3,\n * secondaryGroupSize : 0,\n * fractionGroupSeparator : '\\xA0', // non-breaking space\n * fractionGroupSize : 0\n * };\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toFormat() decimal places not an integer: {dp}'\n * 'toFormat() decimal places out of range: {dp}'\n * 'toFormat() rounding mode not an integer: {rm}'\n * 'toFormat() rounding mode out of range: {rm}'\n */\n P.toFormat = function ( dp, rm ) {\n var str = format( this, dp != null && isValidInt( dp, 0, MAX, 21 )\n ? ~~dp + this.e + 1 : null, rm, 21 );\n\n if ( this.c ) {\n var i,\n arr = str.split('.'),\n g1 = +FORMAT.groupSize,\n g2 = +FORMAT.secondaryGroupSize,\n groupSeparator = FORMAT.groupSeparator,\n intPart = arr[0],\n fractionPart = arr[1],\n isNeg = this.s < 0,\n intDigits = isNeg ? intPart.slice(1) : intPart,\n len = intDigits.length;\n\n if (g2) i = g1, g1 = g2, g2 = i, len -= i;\n\n if ( g1 > 0 && len > 0 ) {\n i = len % g1 || g1;\n intPart = intDigits.substr( 0, i );\n\n for ( ; i < len; i += g1 ) {\n intPart += groupSeparator + intDigits.substr( i, g1 );\n }\n\n if ( g2 > 0 ) intPart += groupSeparator + intDigits.slice(i);\n if (isNeg) intPart = '-' + intPart;\n }\n\n str = fractionPart\n ? intPart + FORMAT.decimalSeparator + ( ( g2 = +FORMAT.fractionGroupSize )\n ? fractionPart.replace( new RegExp( '\\\\d{' + g2 + '}\\\\B', 'g' ),\n '$&' + FORMAT.fractionGroupSeparator )\n : fractionPart )\n : intPart;\n }\n\n return str;\n };\n\n\n /*\n * Return a string array representing the value of this BigNumber as a simple fraction with\n * an integer numerator and an integer denominator. The denominator will be a positive\n * non-zero value less than or equal to the specified maximum denominator. If a maximum\n * denominator is not specified, the denominator will be the lowest value necessary to\n * represent the number exactly.\n *\n * [md] {number|string|BigNumber} Integer >= 1 and < Infinity. The maximum denominator.\n *\n * 'toFraction() max denominator not an integer: {md}'\n * 'toFraction() max denominator out of range: {md}'\n */\n P.toFraction = function (md) {\n var arr, d0, d2, e, exp, n, n0, q, s,\n k = ERRORS,\n x = this,\n xc = x.c,\n d = new BigNumber(ONE),\n n1 = d0 = new BigNumber(ONE),\n d1 = n0 = new BigNumber(ONE);\n\n if ( md != null ) {\n ERRORS = false;\n n = new BigNumber(md);\n ERRORS = k;\n\n if ( !( k = n.isInt() ) || n.lt(ONE) ) {\n\n if (ERRORS) {\n raise( 22,\n 'max denominator ' + ( k ? 'out of range' : 'not an integer' ), md );\n }\n\n // ERRORS is false:\n // If md is a finite non-integer >= 1, round it to an integer and use it.\n md = !k && n.c && round( n, n.e + 1, 1 ).gte(ONE) ? n : null;\n }\n }\n\n if ( !xc ) return x.toString();\n s = coeffToString(xc);\n\n // Determine initial denominator.\n // d is a power of 10 and the minimum max denominator that specifies the value exactly.\n e = d.e = s.length - x.e - 1;\n d.c[0] = POWS_TEN[ ( exp = e % LOG_BASE ) < 0 ? LOG_BASE + exp : exp ];\n md = !md || n.cmp(d) > 0 ? ( e > 0 ? d : n1 ) : n;\n\n exp = MAX_EXP;\n MAX_EXP = 1 / 0;\n n = new BigNumber(s);\n\n // n0 = d1 = 0\n n0.c[0] = 0;\n\n for ( ; ; ) {\n q = div( n, d, 0, 1 );\n d2 = d0.plus( q.times(d1) );\n if ( d2.cmp(md) == 1 ) break;\n d0 = d1;\n d1 = d2;\n n1 = n0.plus( q.times( d2 = n1 ) );\n n0 = d2;\n d = n.minus( q.times( d2 = d ) );\n n = d2;\n }\n\n d2 = div( md.minus(d0), d1, 0, 1 );\n n0 = n0.plus( d2.times(n1) );\n d0 = d0.plus( d2.times(d1) );\n n0.s = n1.s = x.s;\n e *= 2;\n\n // Determine which fraction is closer to x, n0/d0 or n1/d1\n arr = div( n1, d1, e, ROUNDING_MODE ).minus(x).abs().cmp(\n div( n0, d0, e, ROUNDING_MODE ).minus(x).abs() ) < 1\n ? [ n1.toString(), d1.toString() ]\n : [ n0.toString(), d0.toString() ];\n\n MAX_EXP = exp;\n return arr;\n };\n\n\n /*\n * Return the value of this BigNumber converted to a number primitive.\n */\n P.toNumber = function () {\n var x = this;\n\n // Ensure zero has correct sign.\n return +x || ( x.s ? x.s * 0 : NaN );\n };\n\n\n /*\n * Return a BigNumber whose value is the value of this BigNumber raised to the power n.\n * If n is negative round according to DECIMAL_PLACES and ROUNDING_MODE.\n * If POW_PRECISION is not 0, round to POW_PRECISION using ROUNDING_MODE.\n *\n * n {number} Integer, -9007199254740992 to 9007199254740992 inclusive.\n * (Performs 54 loop iterations for n of 9007199254740992.)\n *\n * 'pow() exponent not an integer: {n}'\n * 'pow() exponent out of range: {n}'\n */\n P.toPower = P.pow = function (n) {\n var k, y,\n i = mathfloor( n < 0 ? -n : +n ),\n x = this;\n\n // Pass ±Infinity to Math.pow if exponent is out of range.\n if ( !isValidInt( n, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 23, 'exponent' ) &&\n ( !isFinite(n) || i > MAX_SAFE_INTEGER && ( n /= 0 ) ||\n parseFloat(n) != n && !( n = NaN ) ) ) {\n return new BigNumber( Math.pow( +x, n ) );\n }\n\n // Truncating each coefficient array to a length of k after each multiplication equates\n // to truncating significant digits to POW_PRECISION + [28, 41], i.e. there will be a\n // minimum of 28 guard digits retained. (Using + 1.5 would give [9, 21] guard digits.)\n k = POW_PRECISION ? mathceil( POW_PRECISION / LOG_BASE + 2 ) : 0;\n y = new BigNumber(ONE);\n\n for ( ; ; ) {\n\n if ( i % 2 ) {\n y = y.times(x);\n if ( !y.c ) break;\n if ( k && y.c.length > k ) y.c.length = k;\n }\n\n i = mathfloor( i / 2 );\n if ( !i ) break;\n\n x = x.times(x);\n if ( k && x.c && x.c.length > k ) x.c.length = k;\n }\n\n if ( n < 0 ) y = ONE.div(y);\n return k ? round( y, POW_PRECISION, ROUNDING_MODE ) : y;\n };\n\n\n /*\n * Return a string representing the value of this BigNumber rounded to sd significant digits\n * using rounding mode rm or ROUNDING_MODE. If sd is less than the number of digits\n * necessary to represent the integer part of the value in fixed-point notation, then use\n * exponential notation.\n *\n * [sd] {number} Significant digits. Integer, 1 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toPrecision() precision not an integer: {sd}'\n * 'toPrecision() precision out of range: {sd}'\n * 'toPrecision() rounding mode not an integer: {rm}'\n * 'toPrecision() rounding mode out of range: {rm}'\n */\n P.toPrecision = function ( sd, rm ) {\n return format( this, sd != null && isValidInt( sd, 1, MAX, 24, 'precision' )\n ? sd | 0 : null, rm, 24 );\n };\n\n\n /*\n * Return a string representing the value of this BigNumber in base b, or base 10 if b is\n * omitted. If a base is specified, including base 10, round according to DECIMAL_PLACES and\n * ROUNDING_MODE. If a base is not specified, and this BigNumber has a positive exponent\n * that is equal to or greater than TO_EXP_POS, or a negative exponent equal to or less than\n * TO_EXP_NEG, return exponential notation.\n *\n * [b] {number} Integer, 2 to 64 inclusive.\n *\n * 'toString() base not an integer: {b}'\n * 'toString() base out of range: {b}'\n */\n P.toString = function (b) {\n var str,\n n = this,\n s = n.s,\n e = n.e;\n\n // Infinity or NaN?\n if ( e === null ) {\n\n if (s) {\n str = 'Infinity';\n if ( s < 0 ) str = '-' + str;\n } else {\n str = 'NaN';\n }\n } else {\n str = coeffToString( n.c );\n\n if ( b == null || !isValidInt( b, 2, 64, 25, 'base' ) ) {\n str = e <= TO_EXP_NEG || e >= TO_EXP_POS\n ? toExponential( str, e )\n : toFixedPoint( str, e );\n } else {\n str = convertBase( toFixedPoint( str, e ), b | 0, 10, s );\n }\n\n if ( s < 0 && n.c[0] ) str = '-' + str;\n }\n\n return str;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber truncated to a whole\n * number.\n */\n P.truncated = P.trunc = function () {\n return round( new BigNumber(this), this.e + 1, 1 );\n };\n\n\n\n /*\n * Return as toString, but do not accept a base argument.\n */\n P.valueOf = P.toJSON = function () {\n return this.toString();\n };\n\n\n // Aliases for BigDecimal methods.\n //P.add = P.plus; // P.add included above\n //P.subtract = P.minus; // P.sub included above\n //P.multiply = P.times; // P.mul included above\n //P.divide = P.div;\n //P.remainder = P.mod;\n //P.compareTo = P.cmp;\n //P.negate = P.neg;\n\n\n if ( configObj != null ) BigNumber.config(configObj);\n\n return BigNumber;\n }\n\n\n // PRIVATE HELPER FUNCTIONS\n\n\n function bitFloor(n) {\n var i = n | 0;\n return n > 0 || n === i ? i : i - 1;\n }\n\n\n // Return a coefficient array as a string of base 10 digits.\n function coeffToString(a) {\n var s, z,\n i = 1,\n j = a.length,\n r = a[0] + '';\n\n for ( ; i < j; ) {\n s = a[i++] + '';\n z = LOG_BASE - s.length;\n for ( ; z--; s = '0' + s );\n r += s;\n }\n\n // Determine trailing zeros.\n for ( j = r.length; r.charCodeAt(--j) === 48; );\n return r.slice( 0, j + 1 || 1 );\n }\n\n\n // Compare the value of BigNumbers x and y.\n function compare( x, y ) {\n var a, b,\n xc = x.c,\n yc = y.c,\n i = x.s,\n j = y.s,\n k = x.e,\n l = y.e;\n\n // Either NaN?\n if ( !i || !j ) return null;\n\n a = xc && !xc[0];\n b = yc && !yc[0];\n\n // Either zero?\n if ( a || b ) return a ? b ? 0 : -j : i;\n\n // Signs differ?\n if ( i != j ) return i;\n\n a = i < 0;\n b = k == l;\n\n // Either Infinity?\n if ( !xc || !yc ) return b ? 0 : !xc ^ a ? 1 : -1;\n\n // Compare exponents.\n if ( !b ) return k > l ^ a ? 1 : -1;\n\n j = ( k = xc.length ) < ( l = yc.length ) ? k : l;\n\n // Compare digit by digit.\n for ( i = 0; i < j; i++ ) if ( xc[i] != yc[i] ) return xc[i] > yc[i] ^ a ? 1 : -1;\n\n // Compare lengths.\n return k == l ? 0 : k > l ^ a ? 1 : -1;\n }\n\n\n /*\n * Return true if n is a valid number in range, otherwise false.\n * Use for argument validation when ERRORS is false.\n * Note: parseInt('1e+1') == 1 but parseFloat('1e+1') == 10.\n */\n function intValidatorNoErrors( n, min, max ) {\n return ( n = truncate(n) ) >= min && n <= max;\n }\n\n\n function isArray(obj) {\n return Object.prototype.toString.call(obj) == '[object Array]';\n }\n\n\n /*\n * Convert string of baseIn to an array of numbers of baseOut.\n * Eg. convertBase('255', 10, 16) returns [15, 15].\n * Eg. convertBase('ff', 16, 10) returns [2, 5, 5].\n */\n function toBaseOut( str, baseIn, baseOut ) {\n var j,\n arr = [0],\n arrL,\n i = 0,\n len = str.length;\n\n for ( ; i < len; ) {\n for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn );\n arr[ j = 0 ] += ALPHABET.indexOf( str.charAt( i++ ) );\n\n for ( ; j < arr.length; j++ ) {\n\n if ( arr[j] > baseOut - 1 ) {\n if ( arr[j + 1] == null ) arr[j + 1] = 0;\n arr[j + 1] += arr[j] / baseOut | 0;\n arr[j] %= baseOut;\n }\n }\n }\n\n return arr.reverse();\n }\n\n\n function toExponential( str, e ) {\n return ( str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str ) +\n ( e < 0 ? 'e' : 'e+' ) + e;\n }\n\n\n function toFixedPoint( str, e ) {\n var len, z;\n\n // Negative exponent?\n if ( e < 0 ) {\n\n // Prepend zeros.\n for ( z = '0.'; ++e; z += '0' );\n str = z + str;\n\n // Positive exponent\n } else {\n len = str.length;\n\n // Append zeros.\n if ( ++e > len ) {\n for ( z = '0', e -= len; --e; z += '0' );\n str += z;\n } else if ( e < len ) {\n str = str.slice( 0, e ) + '.' + str.slice(e);\n }\n }\n\n return str;\n }\n\n\n function truncate(n) {\n n = parseFloat(n);\n return n < 0 ? mathceil(n) : mathfloor(n);\n }\n\n\n // EXPORT\n\n\n BigNumber = another();\n\n // AMD.\n if ( typeof define == 'function' && define.amd ) {\n define( function () { return BigNumber; } );\n\n // Node and other environments that support module.exports.\n } else if ( typeof module != 'undefined' && module.exports ) {\n module.exports = BigNumber;\n if ( !crypto ) try { crypto = require('crypto'); } catch (e) {}\n\n // Browser.\n } else {\n global.BigNumber = BigNumber;\n }\n})(this);\n", - "var web3 = require('./lib/web3');\nweb3.providers.HttpProvider = require('./lib/web3/httpprovider');\nweb3.providers.QtSyncProvider = require('./lib/web3/qtsync');\nweb3.eth.contract = require('./lib/web3/contract');\nweb3.eth.namereg = require('./lib/web3/namereg');\nweb3.eth.sendIBANTransaction = require('./lib/web3/transfer');\n\n// dont override global variable\nif (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {\n window.web3 = web3;\n}\n\nmodule.exports = web3;\n\n" + "var web3 = require('./lib/web3');\n\nweb3.providers.HttpProvider = require('./lib/web3/httpprovider');\nweb3.providers.IpcProvider = require('./lib/web3/ipcprovider');\n\nweb3.eth.contract = require('./lib/web3/contract');\nweb3.eth.namereg = require('./lib/web3/namereg');\nweb3.eth.sendIBANTransaction = require('./lib/web3/transfer');\n\n// dont override global variable\nif (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {\n window.web3 = web3;\n}\n\nmodule.exports = web3;\n\n" ] } \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/web3.min.js b/libjsqrc/ethereumjs/dist/web3.min.js index 3d9c300e8..14a3dc353 100644 --- a/libjsqrc/ethereumjs/dist/web3.min.js +++ b/libjsqrc/ethereumjs/dist/web3.min.js @@ -1,4 +1,4 @@ -require=function t(e,n,r){function i(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(o)return o(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return i(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;ao;o+=64)n.push(this._outputFormatter(new a(t.dynamicPart().substr(o+64,64))));return n}return this._outputFormatter(t)},u.prototype.sliceParam=function(t,e,n){return"bytes"===this._mode?a.decodeBytes(t,e):s(n)?a.decodeArray(t,e):a.decodeParam(t,e)};var c=function(t){this._types=t};c.prototype._requireType=function(t){var e=this._types.filter(function(e){return e.isType(t)})[0];if(!e)throw Error("invalid solidity type!: "+t);return e},c.prototype._formatInput=function(t,e){return this._requireType(t).formatInput(e,s(t))},c.prototype.encodeParam=function(t,e){return this._formatInput(t,e).encode()},c.prototype.encodeParams=function(t,e){var n=this,r=t.map(function(t,r){return n._formatInput(t,e[r])});return a.encodeList(r)},c.prototype.decodeParam=function(t,e){return this.decodeParams([t],e)[0]},c.prototype.decodeParams=function(t,e){var n=this;return t.map(function(t,r){var i=n._requireType(t),o=i.sliceParam(e,r,t);return i.formatOutput(o,s(t))})};var l=new c([new u({name:"address",match:"strict",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputAddress}),new u({name:"bool",match:"strict",mode:"value",inputFormatter:o.formatInputBool,outputFormatter:o.formatOutputBool}),new u({name:"int",match:"prefix",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputInt}),new u({name:"uint",match:"prefix",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputUInt}),new u({name:"bytes",match:"strict",mode:"bytes",inputFormatter:o.formatInputDynamicBytes,outputFormatter:o.formatOutputDynamicBytes}),new u({name:"bytes",match:"prefix",mode:"value",inputFormatter:o.formatInputBytes,outputFormatter:o.formatOutputBytes}),new u({name:"string",match:"strict",mode:"bytes",inputFormatter:o.formatInputString,outputFormatter:o.formatOutputString}),new u({name:"real",match:"prefix",mode:"value",inputFormatter:o.formatInputReal,outputFormatter:o.formatOutputReal}),new u({name:"ureal",match:"prefix",mode:"value",inputFormatter:o.formatInputReal,outputFormatter:o.formatOutputUReal})]);e.exports=l},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(t,e,n){var r=t("bignumber.js"),i=t("../utils/utils"),o=t("../utils/config"),a=t("./param"),s=function(t){var e=2*o.ETH_PADDING;r.config(o.ETH_BIGNUMBER_ROUNDING_MODE);var n=i.padLeft(i.toTwosComplement(t).round().toString(16),e);return new a(n)},u=function(t){var e=i.padRight(i.toHex(t).substr(2),64);return new a(e)},c=function(t){t=i.toHex(t).substr(2);var e=Math.floor((t.length+63)/64),n=i.padRight(t,64*e),r=Math.floor(t.length/2);return new a(s(r).value+n,32)},l=function(t){var e=i.fromAscii(t).substr(2),n=Math.floor((e.length+63)/64);return e=i.padRight(e,64*n),new a(s(t.length).value+e,32)},f=function(t){var e="000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0");return new a(e)},p=function(t){return s(new r(t).times(new r(2).pow(128)))},h=function(t){return"1"===new r(t.substr(0,1),16).toString(2).substr(0,1)},m=function(t){var e=t.staticPart()||"0";return h(e)?new r(e,16).minus(new r("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new r(e,16)},d=function(t){var e=t.staticPart()||"0";return new r(e,16)},g=function(t){return m(t).dividedBy(new r(2).pow(128))},y=function(t){return d(t).dividedBy(new r(2).pow(128))},v=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t.staticPart()?!0:!1},w=function(t){return"0x"+t.staticPart()},b=function(t){var e=2*new r(t.dynamicPart().slice(0,64),16).toNumber();return"0x"+t.dynamicPart().substr(64,e)},_=function(t){var e=2*new r(t.dynamicPart().slice(0,64),16).toNumber();return i.toAscii(t.dynamicPart().substr(64,e))},x=function(t){var e=t.staticPart();return"0x"+e.slice(e.length-40,e.length)};e.exports={formatInputInt:s,formatInputBytes:u,formatInputDynamicBytes:c,formatInputString:l,formatInputBool:f,formatInputReal:p,formatOutputInt:m,formatOutputUInt:d,formatOutputReal:g,formatOutputUReal:y,formatOutputBool:v,formatOutputBytes:w,formatOutputDynamicBytes:b,formatOutputString:_,formatOutputAddress:x}},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),i=function(t,e){this.value=t||"",this.offset=e};i.prototype.dynamicPartLength=function(){return this.dynamicPart().length/2},i.prototype.withOffset=function(t){return new i(this.value,t)},i.prototype.combine=function(t){return new i(this.value+t.value)},i.prototype.isDynamic=function(){return this.value.length>64||void 0!==this.offset},i.prototype.offsetAsBytes=function(){return this.isDynamic()?r.padLeft(r.toTwosComplement(this.offset).toString(16),64):""},i.prototype.staticPart=function(){return this.isDynamic()?this.offsetAsBytes():this.value},i.prototype.dynamicPart=function(){return this.isDynamic()?this.value:""},i.prototype.encode=function(){return this.staticPart()+this.dynamicPart()},i.encodeList=function(t){var e=32*t.length,n=t.map(function(t){if(!t.isDynamic())return t;var n=e;return e+=t.dynamicPartLength(),t.withOffset(n)});return n.reduce(function(t,e){return t+e.dynamicPart()},n.reduce(function(t,e){return t+e.staticPart()},""))},i.decodeParam=function(t,e){return e=e||0,new i(t.substr(64*e,64))};var o=function(t,e){return parseInt("0x"+t.substr(64*e,64))};i.decodeBytes=function(t,e){e=e||0;var n=o(t,e),r=parseInt("0x"+t.substr(2*n,64));return r=Math.floor((r+31)/32),new i(t.substr(2*n,64*(1+r)),0)},i.decodeArray=function(t,e){e=e||0;var n=o(t,e),r=parseInt("0x"+t.substr(2*n,64));return new i(t.substr(2*n,64*(r+1)),0)},e.exports=i},{"../utils/utils":7}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e,n){var r=t("bignumber.js"),i=["wei","kwei","Mwei","Gwei","szabo","finney","femtoether","picoether","nanoether","microether","milliether","nano","micro","milli","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:i,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:r.ROUND_DOWN},ETH_POLLING_TIMEOUT:500,defaultBlock:"latest",defaultAccount:void 0}},{"bignumber.js":"bignumber.js"}],6:[function(t,e,n){var r=t("./utils"),i=t("crypto-js/sha3");e.exports=function(t,e){return"0x"!==t.substr(0,2)||e||(console.warn("requirement of using web3.fromAscii before sha3 is deprecated"),console.warn("new usage: 'web3.sha3(\"hello\")'"),console.warn("see https://github.com/ethereum/web3.js/pull/205"),console.warn("if you need to hash hex value, you can do 'sha3(\"0xfff\", true)'"),t=r.toAscii(t)),i(t,{outputLength:256}).toString()}},{"./utils":7,"crypto-js/sha3":34}],7:[function(t,e,n){var r=t("bignumber.js"),i={wei:"1",kwei:"1000",ada:"1000",femtoether:"1000",mwei:"1000000",babbage:"1000000",picoether:"1000000",gwei:"1000000000",shannon:"1000000000",nanoether:"1000000000",nano:"1000000000",szabo:"1000000000000",microether:"1000000000000",micro:"1000000000000",finney:"1000000000000000",milliether:"1000000000000000",milli:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},o=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t,e,n){return t+new Array(e-t.length+1).join(n?n:"0")},s=function(t){var e="",n=0,r=t.length;for("0x"===t.substring(0,2)&&(n=2);r>n;n+=2){var i=parseInt(t.substr(n,2),16);e+=String.fromCharCode(i)}return e},u=function(t){for(var e="",n=0;n0&&c(i),r)return i.watch(r)})};l.prototype.watch=function(t){return this.callbacks.push(t),this.filterId&&(u(this,t),c(this)),this},l.prototype.stopWatching=function(){r.getInstance().stopPolling(this.filterId),this.implementation.uninstallFilter(this.filterId,function(){}),this.callbacks=[]},l.prototype.get=function(t){var e=this;if(!o.isFunction(t)){var n=this.implementation.getLogs(this.filterId);return n.map(function(t){return e.formatter?e.formatter(t):t})}return this.implementation.getLogs(this.filterId,function(n,r){n?t(n):t(null,r.map(function(t){return e.formatter?e.formatter(t):t}))}),this},e.exports=l},{"../utils/utils":7,"./formatters":18,"./requestmanager":28}],18:[function(t,e,n){var r=t("../utils/utils"),i=t("../utils/config"),o=function(t){return r.toBigNumber(t)},a=function(t){return"latest"===t||"pending"===t||"earliest"===t},s=function(t){return void 0===t?i.defaultBlock:u(t)},u=function(t){return void 0===t?void 0:a(t)?t:r.toHex(t)},c=function(t){return t.from=t.from||i.defaultAccount,t.code&&(t.data=t.code,delete t.code),["gasPrice","gas","value","nonce"].filter(function(e){return void 0!==t[e]}).forEach(function(e){t[e]=r.fromDecimal(t[e])}),t},l=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),t.nonce=r.toDecimal(t.nonce),t.gas=r.toDecimal(t.gas),t.gasPrice=r.toBigNumber(t.gasPrice),t.value=r.toBigNumber(t.value),t},f=function(t){return t.gasLimit=r.toDecimal(t.gasLimit),t.gasUsed=r.toDecimal(t.gasUsed),t.size=r.toDecimal(t.size),t.timestamp=r.toDecimal(t.timestamp),null!==t.number&&(t.number=r.toDecimal(t.number)),t.difficulty=r.toBigNumber(t.difficulty),t.totalDifficulty=r.toBigNumber(t.totalDifficulty),r.isArray(t.transactions)&&t.transactions.forEach(function(t){return r.isString(t)?void 0:l(t)}),t},p=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),null!==t.logIndex&&(t.logIndex=r.toDecimal(t.logIndex)),t},h=function(t){return t.payload=r.toHex(t.payload),t.ttl=r.fromDecimal(t.ttl),t.workToProve=r.fromDecimal(t.workToProve),t.priority=r.fromDecimal(t.priority),r.isArray(t.topics)||(t.topics=t.topics?[t.topics]:[]),t.topics=t.topics.map(function(t){return r.fromAscii(t)}),t},m=function(t){return t.expiry=r.toDecimal(t.expiry),t.sent=r.toDecimal(t.sent),t.ttl=r.toDecimal(t.ttl),t.workProved=r.toDecimal(t.workProved),t.payloadRaw=t.payload,t.payload=r.toAscii(t.payload),r.isJson(t.payload)&&(t.payload=JSON.parse(t.payload)),t.topics||(t.topics=[]),t.topics=t.topics.map(function(t){return r.toAscii(t)}),t};e.exports={inputDefaultBlockNumberFormatter:s,inputBlockNumberFormatter:u,inputTransactionFormatter:c,inputPostFormatter:h,outputBigNumberFormatter:o,outputTransactionFormatter:l,outputBlockFormatter:f,outputLogFormatter:p,outputPostFormatter:m}},{"../utils/config":5,"../utils/utils":7}],19:[function(t,e,n){var r=t("../web3"),i=t("../solidity/coder"),o=t("../utils/utils"),a=t("./formatters"),s=t("../utils/sha3"),u=function(t,e){this._inputTypes=t.inputs.map(function(t){return t.type}),this._outputTypes=t.outputs.map(function(t){return t.type}),this._constant=t.constant,this._name=o.transformToFullName(t),this._address=e};u.prototype.extractCallback=function(t){return o.isFunction(t[t.length-1])?t.pop():void 0},u.prototype.extractDefaultBlock=function(t){return t.length>this._inputTypes.length&&!o.isObject(t[t.length-1])?a.inputDefaultBlockNumberFormatter(t.pop()):void 0},u.prototype.toPayload=function(t){var e={};return t.length>this._inputTypes.length&&o.isObject(t[t.length-1])&&(e=t[t.length-1]),e.to=this._address,e.data="0x"+this.signature()+i.encodeParams(this._inputTypes,t),e},u.prototype.signature=function(){return s(this._name).slice(0,8)},u.prototype.unpackOutput=function(t){if(t){t=t.length>=2?t.slice(2):t;var e=i.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},u.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.extractDefaultBlock(t),i=this.toPayload(t);if(!e){var o=r.eth.call(i,n);return this.unpackOutput(o)}var a=this;r.eth.call(i,n,function(t,n){e(t,a.unpackOutput(n))})},u.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):r.eth.sendTransaction(n)},u.prototype.estimateGas=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.estimateGas(n,e):r.eth.estimateGas(n)},u.prototype.displayName=function(){return o.extractDisplayName(this._name)},u.prototype.typeName=function(){return o.extractTypeName(this._name)},u.prototype.request=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t),r=this.unpackOutput.bind(this);return{method:this._constant?"eth_call":"eth_sendTransaction",callback:e,params:[n],format:r}},u.prototype.execute=function(){var t=!this._constant;return t?this.sendTransaction.apply(this,Array.prototype.slice.call(arguments)):this.call.apply(this,Array.prototype.slice.call(arguments))},u.prototype.attachToContract=function(t){var e=this.execute.bind(this);e.request=this.request.bind(this),e.call=this.call.bind(this),e.sendTransaction=this.sendTransaction.bind(this),e.estimateGas=this.estimateGas.bind(this);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=u},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":18}],20:[function(t,e,n){"use strict";var r="undefined"!=typeof window&&window.XMLHttpRequest?window.XMLHttpRequest:t("xmlhttprequest").XMLHttpRequest,i=t("./errors"),o=function(t){this.host=t||"http://localhost:8545"};o.prototype.send=function(t){var e=new r;e.open("POST",this.host,!1),e.setRequestHeader("Content-type","application/json");try{e.send(JSON.stringify(t))}catch(n){throw i.InvalidConnection(this.host)}var o=e.responseText;try{o=JSON.parse(o)}catch(a){throw i.InvalidResponse(o)}return o},o.prototype.sendAsync=function(t,e){var n=new r;n.onreadystatechange=function(){if(4===n.readyState){var t=n.responseText,r=null;try{t=JSON.parse(t)}catch(o){r=i.InvalidResponse(t)}e(r,t)}},n.open("POST",this.host,!0),n.setRequestHeader("Content-type","application/json");try{n.send(JSON.stringify(t))}catch(o){e(i.InvalidConnection(this.host))}},e.exports=o},{"./errors":14,xmlhttprequest:4}],21:[function(t,e,n){var r=t("../utils/utils"),i=function(t){this._iban=t};i.prototype.isValid=function(){return r.isIBAN(this._iban)},i.prototype.isDirect=function(){return 34===this._iban.length},i.prototype.isIndirect=function(){return 20===this._iban.length},i.prototype.checksum=function(){return this._iban.substr(2,2)},i.prototype.institution=function(){return this.isIndirect()?this._iban.substr(7,4):""},i.prototype.client=function(){return this.isIndirect()?this._iban.substr(11):""},i.prototype.address=function(){return this.isDirect()?this._iban.substr(4):""},e.exports=i},{"../utils/utils":7}],22:[function(t,e,n){var r=function(){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,void(this.messageId=1))};r.getInstance=function(){var t=new r;return t},r.prototype.toPayload=function(t,e){return t||console.error("jsonrpc method should be specified!"),{jsonrpc:"2.0",method:t,params:e||[],id:this.messageId++ -}},r.prototype.isValidResponse=function(t){return!!t&&!t.error&&"2.0"===t.jsonrpc&&"number"==typeof t.id&&void 0!==t.result},r.prototype.toBatchPayload=function(t){var e=this;return t.map(function(t){return e.toPayload(t.method,t.params)})},e.exports=r},{}],23:[function(t,e,n){var r=t("./requestmanager"),i=t("../utils/utils"),o=t("./errors"),a=function(t){this.name=t.name,this.call=t.call,this.params=t.params||0,this.inputFormatter=t.inputFormatter,this.outputFormatter=t.outputFormatter};a.prototype.getCall=function(t){return i.isFunction(this.call)?this.call(t):this.call},a.prototype.extractCallback=function(t){return i.isFunction(t[t.length-1])?t.pop():void 0},a.prototype.validateArgs=function(t){if(t.length!==this.params)throw o.InvalidNumberOfParams()},a.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter.map(function(e,n){return e?e(t[n]):t[n]}):t},a.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},a.prototype.attachToObject=function(t){var e=this.send.bind(this);e.request=this.request.bind(this),e.call=this.call;var n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},a.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},a.prototype.request=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));return t.format=this.formatOutput.bind(this),t},a.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return r.getInstance().sendAsync(t,function(n,r){t.callback(n,e.formatOutput(r))})}return this.formatOutput(r.getInstance().send(t))},e.exports=a},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],24:[function(t,e,n){var r=t("./contract"),i="0xc6d9d2cd449a754c494264e1809c50e34d64562b",o=[{constant:!0,inputs:[{name:"_owner",type:"address"}],name:"name",outputs:[{name:"o_name",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"owner",outputs:[{name:"",type:"address"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"content",outputs:[{name:"",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"addr",outputs:[{name:"",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"reserve",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"subRegistrar",outputs:[{name:"o_subRegistrar",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_newOwner",type:"address"}],name:"transfer",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_registrar",type:"address"}],name:"setSubRegistrar",outputs:[],type:"function"},{constant:!1,inputs:[],name:"Registrar",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_a",type:"address"},{name:"_primary",type:"bool"}],name:"setAddress",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_content",type:"bytes32"}],name:"setContent",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"disown",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"register",outputs:[{name:"",type:"address"}],type:"function"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"}],name:"Changed",type:"event"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"},{indexed:!0,name:"addr",type:"address"}],name:"PrimaryChanged",type:"event"}];e.exports=r(o).at(i)},{"./contract":12}],25:[function(t,e,n){var r=t("../utils/utils"),i=t("./property"),o=[],a=[new i({name:"listening",getter:"net_listening"}),new i({name:"peerCount",getter:"net_peerCount",outputFormatter:r.toDecimal})];e.exports={methods:o,properties:a}},{"../utils/utils":7,"./property":26}],26:[function(t,e,n){var r=t("./requestmanager"),i=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};i.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},i.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},i.prototype.attachToObject=function(t){var e={get:this.get.bind(this)},n=this.name.split("."),r=n[0];n.length>1&&(t[n[0]]=t[n[0]]||{},t=t[n[0]],r=n[1]),Object.defineProperty(t,r,e);var i=function(t,e){return t+e.charAt(0).toUpperCase()+e.slice(1)};t[i("get",r)]=this.getAsync.bind(this)},i.prototype.get=function(){return this.formatOutput(r.getInstance().send({method:this.getter}))},i.prototype.getAsync=function(t){var e=this;r.getInstance().sendAsync({method:this.getter},function(n,r){return n?t(n):void t(n,e.formatOutput(r))})},e.exports=i},{"./requestmanager":28}],27:[function(t,e,n){var r=function(){};r.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=r},{}],28:[function(t,e,n){var r=t("./jsonrpc"),i=t("../utils/utils"),o=t("../utils/config"),a=t("./errors"),s=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls={},this.timeout=null,void(this.isPolling=!1))};s.getInstance=function(){var t=new s;return t},s.prototype.send=function(t){if(!this.provider)return console.error(a.InvalidProvider()),null;var e=r.getInstance().toPayload(t.method,t.params),n=this.provider.send(e);if(!r.getInstance().isValidResponse(n))throw a.InvalidResponse(n);return n.result},s.prototype.sendAsync=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(n,function(t,n){return t?e(t):r.getInstance().isValidResponse(n)?void e(null,n.result):e(a.InvalidResponse(n))})},s.prototype.sendBatch=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toBatchPayload(t);this.provider.sendAsync(n,function(t,n){return t?e(t):i.isArray(n)?void e(t,n):e(a.InvalidResponse(n))})},s.prototype.setProvider=function(t){this.provider=t,this.provider&&!this.isPolling&&(this.poll(),this.isPolling=!0)},s.prototype.startPolling=function(t,e,n,r){this.polls["poll_"+e]={data:t,id:e,callback:n,uninstall:r}},s.prototype.stopPolling=function(t){delete this.polls["poll_"+t]},s.prototype.reset=function(){for(var t in this.polls)this.polls[t].uninstall();this.polls={},this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},s.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),o.ETH_POLLING_TIMEOUT),0!==Object.keys(this.polls).length){if(!this.provider)return void console.error(a.InvalidProvider());var t=[],e=[];for(var n in this.polls)t.push(this.polls[n].data),e.push(n);if(0!==t.length){var s=r.getInstance().toBatchPayload(t),u=this;this.provider.sendAsync(s,function(t,n){if(!t){if(!i.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){var r=e[n];return u.polls[r]?(t.callback=u.polls[r].callback,t):!1}).filter(function(t){return!!t}).filter(function(t){var e=r.getInstance().isValidResponse(t);return e||t.callback(a.InvalidResponse(t)),e}).filter(function(t){return i.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}}},e.exports=s},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":22}],29:[function(t,e,n){var r=t("./method"),i=t("./formatters"),o=new r({name:"post",call:"shh_post",params:1,inputFormatter:[i.inputPostFormatter]}),a=new r({name:"newIdentity",call:"shh_newIdentity",params:0}),s=new r({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new r({name:"newGroup",call:"shh_newGroup",params:0}),c=new r({name:"addToGroup",call:"shh_addToGroup",params:0}),l=[o,a,s,u,c];e.exports={methods:l}},{"./formatters":18,"./method":23}],30:[function(t,e,n){var r=t("../web3"),i=t("./icap"),o=t("./namereg"),a=t("./contract"),s=function(t,e,n,r){var a=new i(e);if(!a.isValid())throw new Error("invalid iban address");if(a.isDirect())return u(t,a.address(),n,r);if(!r){var s=o.addr(a.institution());return c(t,s,n,a.client())}o.addr(a.insitution(),function(e,i){return c(t,i,n,a.client(),r)})},u=function(t,e,n,i){return r.eth.sendTransaction({address:e,from:t,value:n},i)},c=function(t,e,n,r,i){var o=[{constant:!1,inputs:[{name:"name",type:"bytes32"}],name:"deposit",outputs:[],type:"function"}];return a(o).at(e).deposit(r,{from:t,value:n},i)};e.exports=s},{"../web3":9,"./contract":12,"./icap":21,"./namereg":24}],31:[function(t,e,n){var r=t("./method"),i=function(){var t=function(t){var e=t[0];switch(e){case"latest":return t.shift(),this.params=0,"eth_newBlockFilter";case"pending":return t.shift(),this.params=0,"eth_newPendingTransactionFilter";default:return"eth_newFilter"}},e=new r({name:"newFilter",call:t,params:1}),n=new r({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),i=new r({name:"getLogs",call:"eth_getFilterLogs",params:1}),o=new r({name:"poll",call:"eth_getFilterChanges",params:1});return[e,n,i,o]},o=function(){var t=new r({name:"newFilter",call:"shh_newFilter",params:1}),e=new r({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),n=new r({name:"getLogs",call:"shh_getMessages",params:1}),i=new r({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,n,i]};e.exports={eth:i,shh:o}},{"./method":23}],32:[function(t,e,n){},{}],33:[function(t,e,n){!function(t,r){"object"==typeof n?e.exports=n=r():"function"==typeof define&&define.amd?define([],r):t.CryptoJS=r()}(this,function(){var t=t||function(t,e){var n={},r=n.lib={},i=r.Base=function(){function t(){}return{extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),o=r.WordArray=i.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:4*t.length},toString:function(t){return(t||s).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes,i=t.sigBytes;if(this.clamp(),r%4)for(var o=0;i>o;o++){var a=n[o>>>2]>>>24-o%4*8&255;e[r+o>>>2]|=a<<24-(r+o)%4*8}else for(var o=0;i>o;o+=4)e[r+o>>>2]=n[o>>>2];return this.sigBytes+=i,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=i.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n,r=[],i=function(e){var e=e,n=987654321,r=4294967295;return function(){n=36969*(65535&n)+(n>>16)&r,e=18e3*(65535&e)+(e>>16)&r;var i=(n<<16)+e&r;return i/=4294967296,i+=.5,i*(t.random()>.5?1:-1)}},a=0;e>a;a+=4){var s=i(4294967296*(n||t.random()));n=987654071*s(),r.push(4294967296*s()|0)}return new o.init(r,e)}}),a=n.enc={},s=a.Hex={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],i=0;n>i;i++){var o=e[i>>>2]>>>24-i%4*8&255;r.push((o>>>4).toString(16)),r.push((15&o).toString(16))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r+=2)n[r>>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new o.init(n,e/2)}},u=a.Latin1={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],i=0;n>i;i++){var o=e[i>>>2]>>>24-i%4*8&255;r.push(String.fromCharCode(o))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r++)n[r>>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new o.init(n,e)}},c=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},l=r.BufferedBlockAlgorithm=i.extend({reset:function(){this._data=new o.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=c.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,i=n.sigBytes,a=this.blockSize,s=4*a,u=i/s;u=e?t.ceil(u):t.max((0|u)-this._minBufferSize,0);var c=u*a,l=t.min(4*c,i);if(c){for(var f=0;c>f;f+=a)this._doProcessBlock(r,f);var p=r.splice(0,c);n.sigBytes-=l}return new o.init(p,l)},clone:function(){var t=i.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),f=(r.Hasher=l.extend({cfg:i.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){l.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},blockSize:16,_createHelper:function(t){return function(e,n){return new t.init(n).finalize(e)}},_createHmacHelper:function(t){return function(e,n){return new f.HMAC.init(t,n).finalize(e)}}}),n.algo={});return n}(Math);return t})},{}],34:[function(t,e,n){!function(r,i,o){"object"==typeof n?e.exports=n=i(t("./core"),t("./x64-core")):"function"==typeof define&&define.amd?define(["./core","./x64-core"],i):i(r.CryptoJS)}(this,function(t){return function(e){var n=t,r=n.lib,i=r.WordArray,o=r.Hasher,a=n.x64,s=a.Word,u=n.algo,c=[],l=[],f=[];!function(){for(var t=1,e=0,n=0;24>n;n++){c[t+5*e]=(n+1)*(n+2)/2%64;var r=e%5,i=(2*t+3*e)%5;t=r,e=i}for(var t=0;5>t;t++)for(var e=0;5>e;e++)l[t+5*e]=e+(2*t+3*e)%5*5;for(var o=1,a=0;24>a;a++){for(var u=0,p=0,h=0;7>h;h++){if(1&o){var m=(1<m?p^=1<t;t++)p[t]=s.create()}();var h=u.SHA3=o.extend({cfg:o.cfg.extend({outputLength:512}),_doReset:function(){for(var t=this._state=[],e=0;25>e;e++)t[e]=new s.init;this.blockSize=(1600-2*this.cfg.outputLength)/32},_doProcessBlock:function(t,e){for(var n=this._state,r=this.blockSize/2,i=0;r>i;i++){var o=t[e+2*i],a=t[e+2*i+1];o=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8);var s=n[i];s.high^=a,s.low^=o}for(var u=0;24>u;u++){for(var h=0;5>h;h++){for(var m=0,d=0,g=0;5>g;g++){var s=n[h+5*g];m^=s.high,d^=s.low}var y=p[h];y.high=m,y.low=d}for(var h=0;5>h;h++)for(var v=p[(h+4)%5],w=p[(h+1)%5],b=w.high,_=w.low,m=v.high^(b<<1|_>>>31),d=v.low^(_<<1|b>>>31),g=0;5>g;g++){var s=n[h+5*g];s.high^=m,s.low^=d}for(var x=1;25>x;x++){var s=n[x],F=s.high,I=s.low,B=c[x];if(32>B)var m=F<>>32-B,d=I<>>32-B;else var m=I<>>64-B,d=F<>>64-B;var N=p[l[x]];N.high=m,N.low=d}var O=p[0],k=n[0];O.high=k.high,O.low=k.low;for(var h=0;5>h;h++)for(var g=0;5>g;g++){var x=h+5*g,s=n[x],A=p[x],P=p[(h+1)%5+5*g],T=p[(h+2)%5+5*g];s.high=A.high^~P.high&T.high,s.low=A.low^~P.low&T.low}var s=n[0],D=f[u];s.high^=D.high,s.low^=D.low}},_doFinalize:function(){var t=this._data,n=t.words,r=(8*this._nDataBytes,8*t.sigBytes),o=32*this.blockSize;n[r>>>5]|=1<<24-r%32,n[(e.ceil((r+1)/o)*o>>>5)-1]|=128,t.sigBytes=4*n.length,this._process();for(var a=this._state,s=this.cfg.outputLength/8,u=s/8,c=[],l=0;u>l;l++){var f=a[l],p=f.high,h=f.low;p=16711935&(p<<8|p>>>24)|4278255360&(p<<24|p>>>8),h=16711935&(h<<8|h>>>24)|4278255360&(h<<24|h>>>8),c.push(h),c.push(p)}return new i.init(c,s)},clone:function(){for(var t=o.clone.call(this),e=t._state=this._state.slice(0),n=0;25>n;n++)e[n]=e[n].clone();return t}});n.SHA3=o._createHelper(h),n.HmacSHA3=o._createHmacHelper(h)}(Math),t.SHA3})},{"./core":33,"./x64-core":35}],35:[function(t,e,n){!function(r,i){"object"==typeof n?e.exports=n=i(t("./core")):"function"==typeof define&&define.amd?define(["./core"],i):i(r.CryptoJS)}(this,function(t){return function(e){{var n=t,r=n.lib,i=r.Base,o=r.WordArray,a=n.x64={};a.Word=i.extend({init:function(t,e){this.high=t,this.low=e}}),a.WordArray=i.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:8*t.length},toX32:function(){for(var t=this.words,e=t.length,n=[],r=0;e>r;r++){var i=t[r];n.push(i.high),n.push(i.low)}return o.create(n,this.sigBytes)},clone:function(){for(var t=i.clone.call(this),e=t.words=this.words.slice(0),n=e.length,r=0;n>r;r++)e[r]=e[r].clone();return t}})}}(),t})},{"./core":33}],"bignumber.js":[function(t,e,n){!function(n){"use strict";function r(t){function e(t,r){var i,o,a,s,u,c,l=this;if(!(l instanceof e))return z&&D(26,"constructor call without new",t),new e(t,r);if(null!=r&&W(r,2,64,C,"base")){if(r=0|r,c=t+"",10==r)return l=new e(t instanceof e?t:c),S(l,j+l.e+1,L);if((s="number"==typeof t)&&0*t!=0||!new RegExp("^-?"+(i="["+x.slice(0,r)+"]+")+"(?:\\."+i+")?$",37>r?"i":"").test(c))return d(l,c,s,r);s?(l.s=0>1/t?(c=c.slice(1),-1):1,z&&c.replace(/^0\.0*|\./,"").length>15&&D(C,_,t),s=!1):l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1,c=n(c,10,r,l.s)}else{if(t instanceof e)return l.s=t.s,l.e=t.e,l.c=(t=t.c)?t.slice():t,void(C=0);if((s="number"==typeof t)&&0*t==0){if(l.s=0>1/t?(t=-t,-1):1,t===~~t){for(o=0,a=t;a>=10;a/=10,o++);return l.e=o,l.c=[t],void(C=0)}c=t+""}else{if(!g.test(c=t+""))return d(l,c,s);l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1}}for((o=c.indexOf("."))>-1&&(c=c.replace(".","")),(a=c.search(/e/i))>0?(0>o&&(o=a),o+=+c.slice(a+1),c=c.substring(0,a)):0>o&&(o=c.length),a=0;48===c.charCodeAt(a);a++);for(u=c.length;48===c.charCodeAt(--u););if(c=c.slice(a,u+1))if(u=c.length,s&&z&&u>15&&D(C,_,l.s*t),o=o-a-1,o>G)l.c=l.e=null;else if(M>o)l.c=[l.e=0];else{if(l.e=o,l.c=[],a=(o+1)%I,0>o&&(a+=I),u>a){for(a&&l.c.push(+c.slice(0,a)),u-=I;u>a;)l.c.push(+c.slice(a,a+=I));c=c.slice(a),a=I-c.length}else a-=u;for(;a--;c+="0");l.c.push(+c)}else l.c=[l.e=0];C=0}function n(t,n,r,i){var a,s,u,l,p,h,m,d=t.indexOf("."),g=j,y=L;for(37>r&&(t=t.toLowerCase()),d>=0&&(u=V,V=0,t=t.replace(".",""),m=new e(r),p=m.pow(t.length-d),V=u,m.c=c(f(o(p.c),p.e),10,n),m.e=m.c.length),h=c(t,r,n),s=u=h.length;0==h[--u];h.pop());if(!h[0])return"0";if(0>d?--s:(p.c=h,p.e=s,p.s=i,p=R(p,m,g,y,n),h=p.c,l=p.r,s=p.e),a=s+g+1,d=h[a],u=n/2,l=l||0>a||null!=h[a+1],l=4>y?(null!=d||l)&&(0==y||y==(p.s<0?3:2)):d>u||d==u&&(4==y||l||6==y&&1&h[a-1]||y==(p.s<0?8:7)),1>a||!h[0])t=l?f("1",-g):"0";else{if(h.length=a,l)for(--n;++h[--a]>n;)h[a]=0,a||(++s,h.unshift(1));for(u=h.length;!h[--u];);for(d=0,t="";u>=d;t+=x.charAt(h[d++]));t=f(t,s)}return t}function h(t,n,r,i){var a,s,u,c,p;if(r=null!=r&&W(r,0,8,i,b)?0|r:L,!t.c)return t.toString();if(a=t.c[0],u=t.e,null==n)p=o(t.c),p=19==i||24==i&&q>=u?l(p,u):f(p,u);else if(t=S(new e(t),n,r),s=t.e,p=o(t.c),c=p.length,19==i||24==i&&(s>=n||q>=s)){for(;n>c;p+="0",c++);p=l(p,s)}else if(n-=u,p=f(p,s),s+1>c){if(--n>0)for(p+=".";n--;p+="0");}else if(n+=s-c,n>0)for(s+1==c&&(p+=".");n--;p+="0");return t.s<0&&a?"-"+p:p}function A(t,n){var r,i,o=0;for(u(t[0])&&(t=t[0]),r=new e(t[0]);++ot||t>n||t!=p(t))&&D(r,(i||"decimal places")+(e>t||t>n?" out of range":" not an integer"),t),!0}function T(t,e,n){for(var r=1,i=e.length;!e[--i];e.pop());for(i=e[0];i>=10;i/=10,r++);return(n=r+n*I-1)>G?t.c=t.e=null:M>n?t.c=[t.e=0]:(t.e=n,t.c=e),t}function D(t,e,n){var r=new Error(["new BigNumber","cmp","config","div","divToInt","eq","gt","gte","lt","lte","minus","mod","plus","precision","random","round","shift","times","toDigits","toExponential","toFixed","toFormat","toFraction","pow","toPrecision","toString","BigNumber"][t]+"() "+e+": "+n);throw r.name="BigNumber Error",C=0,r}function S(t,e,n,r){var i,o,a,s,u,c,l,f=t.c,p=N;if(f){t:{for(i=1,s=f[0];s>=10;s/=10,i++);if(o=e-i,0>o)o+=I,a=e,u=f[c=0],l=u/p[i-a-1]%10|0;else if(c=y((o+1)/I),c>=f.length){if(!r)break t;for(;f.length<=c;f.push(0));u=l=0,i=1,o%=I,a=o-I+1}else{for(u=s=f[c],i=1;s>=10;s/=10,i++);o%=I,a=o-I+i,l=0>a?0:u/p[i-a-1]%10|0}if(r=r||0>e||null!=f[c+1]||(0>a?u:u%p[i-a-1]),r=4>n?(l||r)&&(0==n||n==(t.s<0?3:2)):l>5||5==l&&(4==n||r||6==n&&(o>0?a>0?u/p[i-a]:0:f[c-1])%10&1||n==(t.s<0?8:7)),1>e||!f[0])return f.length=0,r?(e-=t.e+1,f[0]=p[e%I],t.e=-e||0):f[0]=t.e=0,t;if(0==o?(f.length=c,s=1,c--):(f.length=c+1,s=p[I-o],f[c]=a>0?v(u/p[i-a]%p[a])*s:0),r)for(;;){if(0==c){for(o=1,a=f[0];a>=10;a/=10,o++);for(a=f[0]+=s,s=1;a>=10;a/=10,s++);o!=s&&(t.e++,f[0]==F&&(f[0]=1));break}if(f[c]+=s,f[c]!=F)break;f[c--]=0,s=1}for(o=f.length;0===f[--o];f.pop());}t.e>G?t.c=t.e=null:t.en?null!=(t=i[n++]):void 0};return a(e="DECIMAL_PLACES")&&W(t,0,k,2,e)&&(j=0|t),r[e]=j,a(e="ROUNDING_MODE")&&W(t,0,8,2,e)&&(L=0|t),r[e]=L,a(e="EXPONENTIAL_AT")&&(u(t)?W(t[0],-k,0,2,e)&&W(t[1],0,k,2,e)&&(q=0|t[0],U=0|t[1]):W(t,-k,k,2,e)&&(q=-(U=0|(0>t?-t:t)))),r[e]=[q,U],a(e="RANGE")&&(u(t)?W(t[0],-k,-1,2,e)&&W(t[1],1,k,2,e)&&(M=0|t[0],G=0|t[1]):W(t,-k,k,2,e)&&(0|t?M=-(G=0|(0>t?-t:t)):z&&D(2,e+" cannot be zero",t))),r[e]=[M,G],a(e="ERRORS")&&(t===!!t||1===t||0===t?(C=0,W=(z=!!t)?P:s):z&&D(2,e+w,t)),r[e]=z,a(e="CRYPTO")&&(t===!!t||1===t||0===t?(J=!(!t||!m||"object"!=typeof m),t&&!J&&z&&D(2,"crypto unavailable",m)):z&&D(2,e+w,t)),r[e]=J,a(e="MODULO_MODE")&&W(t,0,9,2,e)&&($=0|t),r[e]=$,a(e="POW_PRECISION")&&W(t,0,k,2,e)&&(V=0|t),r[e]=V,a(e="FORMAT")&&("object"==typeof t?X=t:z&&D(2,e+" not an object",t)),r[e]=X,r},e.max=function(){return A(arguments,E.lt)},e.min=function(){return A(arguments,E.gt)},e.random=function(){var t=9007199254740992,n=Math.random()*t&2097151?function(){return v(Math.random()*t)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)};return function(t){var r,i,o,a,s,u=0,c=[],l=new e(H);if(t=null!=t&&W(t,0,k,14)?0|t:j,a=y(t/I),J)if(m&&m.getRandomValues){for(r=m.getRandomValues(new Uint32Array(a*=2));a>u;)s=131072*r[u]+(r[u+1]>>>11),s>=9e15?(i=m.getRandomValues(new Uint32Array(2)),r[u]=i[0],r[u+1]=i[1]):(c.push(s%1e14),u+=2);u=a/2}else if(m&&m.randomBytes){for(r=m.randomBytes(a*=7);a>u;)s=281474976710656*(31&r[u])+1099511627776*r[u+1]+4294967296*r[u+2]+16777216*r[u+3]+(r[u+4]<<16)+(r[u+5]<<8)+r[u+6],s>=9e15?m.randomBytes(7).copy(r,u):(c.push(s%1e14),u+=7);u=a/7}else z&&D(14,"crypto unavailable",m);if(!u)for(;a>u;)s=n(),9e15>s&&(c[u++]=s%1e14);for(a=c[--u],t%=I,a&&t&&(s=N[I-t],c[u]=v(a/s)*s);0===c[u];c.pop(),u--);if(0>u)c=[o=0];else{for(o=-1;0===c[0];c.shift(),o-=I);for(u=1,s=c[0];s>=10;s/=10,u++);I>u&&(o-=I-u)}return l.e=o,l.c=c,l}}(),R=function(){function t(t,e,n){var r,i,o,a,s=0,u=t.length,c=e%O,l=e/O|0;for(t=t.slice();u--;)o=t[u]%O,a=t[u]/O|0,r=l*o+a*c,i=c*o+r%O*O+s,s=(i/n|0)+(r/O|0)+l*a,t[u]=i%n;return s&&t.unshift(s),t}function n(t,e,n,r){var i,o;if(n!=r)o=n>r?1:-1;else for(i=o=0;n>i;i++)if(t[i]!=e[i]){o=t[i]>e[i]?1:-1;break}return o}function r(t,e,n,r){for(var i=0;n--;)t[n]-=i,i=t[n]1;t.shift());}return function(o,a,s,u,c){var l,f,p,h,m,d,g,y,w,b,_,x,B,N,O,k,A,P=o.s==a.s?1:-1,T=o.c,D=a.c;if(!(T&&T[0]&&D&&D[0]))return new e(o.s&&a.s&&(T?!D||T[0]!=D[0]:D)?T&&0==T[0]||!D?0*P:P/0:0/0);for(y=new e(P),w=y.c=[],f=o.e-a.e,P=s+f+1,c||(c=F,f=i(o.e/I)-i(a.e/I),P=P/I|0),p=0;D[p]==(T[p]||0);p++);if(D[p]>(T[p]||0)&&f--,0>P)w.push(1),h=!0;else{for(N=T.length,k=D.length,p=0,P+=2,m=v(c/(D[0]+1)),m>1&&(D=t(D,m,c),T=t(T,m,c),k=D.length,N=T.length),B=k,b=T.slice(0,k),_=b.length;k>_;b[_++]=0);A=D.slice(),A.unshift(0),O=D[0],D[1]>=c/2&&O++;do{if(m=0,l=n(D,b,k,_),0>l){if(x=b[0],k!=_&&(x=x*c+(b[1]||0)),m=v(x/O),m>1)for(m>=c&&(m=c-1),d=t(D,m,c),g=d.length,_=b.length;1==n(d,b,g,_);)m--,r(d,g>k?A:D,g,c),g=d.length,l=1;else 0==m&&(l=m=1),d=D.slice(),g=d.length;if(_>g&&d.unshift(0),r(b,d,_,c),_=b.length,-1==l)for(;n(D,b,k,_)<1;)m++,r(b,_>k?A:D,_,c),_=b.length}else 0===l&&(m++,b=[0]);w[p++]=m,b[0]?b[_++]=T[B]||0:(b=[T[B]],_=1)}while((B++=10;P/=10,p++);S(y,s+(y.e=p+f*I-1)+1,u,h)}else y.e=f,y.r=+h;return y}}(),d=function(){var t=/^(-?)0([xbo])/i,n=/^([^.]+)\.$/,r=/^\.([^.]+)$/,i=/^-?(Infinity|NaN)$/,o=/^\s*\+|^\s+|\s+$/g;return function(a,s,u,c){var l,f=u?s:s.replace(o,"");if(i.test(f))a.s=isNaN(f)?null:0>f?-1:1;else{if(!u&&(f=f.replace(t,function(t,e,n){return l="x"==(n=n.toLowerCase())?16:"b"==n?2:8,c&&c!=l?t:e}),c&&(l=c,f=f.replace(n,"$1").replace(r,"0.$1")),s!=f))return new e(f,l);z&&D(C,"not a"+(c?" base "+c:"")+" number",s),a.s=null}a.c=a.e=null,C=0}}(),E.absoluteValue=E.abs=function(){var t=new e(this);return t.s<0&&(t.s=1),t},E.ceil=function(){return S(new e(this),this.e+1,2)},E.comparedTo=E.cmp=function(t,n){return C=1,a(this,new e(t,n))},E.decimalPlaces=E.dp=function(){var t,e,n=this.c;if(!n)return null;if(t=((e=n.length-1)-i(this.e/I))*I,e=n[e])for(;e%10==0;e/=10,t--);return 0>t&&(t=0),t},E.dividedBy=E.div=function(t,n){return C=3,R(this,new e(t,n),j,L)},E.dividedToIntegerBy=E.divToInt=function(t,n){return C=4,R(this,new e(t,n),0,1)},E.equals=E.eq=function(t,n){return C=5,0===a(this,new e(t,n))},E.floor=function(){return S(new e(this),this.e+1,3)},E.greaterThan=E.gt=function(t,n){return C=6,a(this,new e(t,n))>0},E.greaterThanOrEqualTo=E.gte=function(t,n){return C=7,1===(n=a(this,new e(t,n)))||0===n},E.isFinite=function(){return!!this.c},E.isInteger=E.isInt=function(){return!!this.c&&i(this.e/I)>this.c.length-2},E.isNaN=function(){return!this.s},E.isNegative=E.isNeg=function(){return this.s<0},E.isZero=function(){return!!this.c&&0==this.c[0]},E.lessThan=E.lt=function(t,n){return C=8,a(this,new e(t,n))<0},E.lessThanOrEqualTo=E.lte=function(t,n){return C=9,-1===(n=a(this,new e(t,n)))||0===n},E.minus=E.sub=function(t,n){var r,o,a,s,u=this,c=u.s;if(C=10,t=new e(t,n),n=t.s,!c||!n)return new e(0/0);if(c!=n)return t.s=-n,u.plus(t);var l=u.e/I,f=t.e/I,p=u.c,h=t.c;if(!l||!f){if(!p||!h)return p?(t.s=-n,t):new e(h?u:0/0);if(!p[0]||!h[0])return h[0]?(t.s=-n,t):new e(p[0]?u:3==L?-0:0)}if(l=i(l),f=i(f),p=p.slice(),c=l-f){for((s=0>c)?(c=-c,a=p):(f=l,a=h),a.reverse(),n=c;n--;a.push(0));a.reverse()}else for(o=(s=(c=p.length)<(n=h.length))?c:n,c=n=0;o>n;n++)if(p[n]!=h[n]){s=p[n]0)for(;n--;p[r++]=0);for(n=F-1;o>c;){if(p[--o]0?(u=s,r=l):(a=-a,r=c),r.reverse();a--;r.push(0));r.reverse()}for(a=c.length,n=l.length,0>a-n&&(r=l,l=c,c=r,n=a),a=0;n;)a=(c[--n]=c[n]+l[n]+a)/F|0,c[n]%=F;return a&&(c.unshift(a),++u),T(t,c,u)},E.precision=E.sd=function(t){var e,n,r=this,i=r.c;if(null!=t&&t!==!!t&&1!==t&&0!==t&&(z&&D(13,"argument"+w,t),t!=!!t&&(t=null)),!i)return null;if(n=i.length-1,e=n*I+1,n=i[n]){for(;n%10==0;n/=10,e--);for(n=i[0];n>=10;n/=10,e++);}return t&&r.e+1>e&&(e=r.e+1),e},E.round=function(t,n){var r=new e(this);return(null==t||W(t,0,k,15))&&S(r,~~t+this.e+1,null!=n&&W(n,0,8,15,b)?0|n:L),r},E.shift=function(t){var n=this;return W(t,-B,B,16,"argument")?n.times("1e"+p(t)):new e(n.c&&n.c[0]&&(-B>t||t>B)?n.s*(0>t?0:1/0):n)},E.squareRoot=E.sqrt=function(){var t,n,r,a,s,u=this,c=u.c,l=u.s,f=u.e,p=j+4,h=new e("0.5");if(1!==l||!c||!c[0])return new e(!l||0>l&&(!c||c[0])?0/0:c?u:1/0);if(l=Math.sqrt(+u),0==l||l==1/0?(n=o(c),(n.length+f)%2==0&&(n+="0"),l=Math.sqrt(n),f=i((f+1)/2)-(0>f||f%2),l==1/0?n="1e"+f:(n=l.toExponential(),n=n.slice(0,n.indexOf("e")+1)+f),r=new e(n)):r=new e(l+""),r.c[0])for(f=r.e,l=f+p,3>l&&(l=0);;)if(s=r,r=h.times(s.plus(R(u,s,p,1))),o(s.c).slice(0,l)===(n=o(r.c)).slice(0,l)){if(r.el&&(g=b,b=_,_=g,a=l,l=h,h=a),a=l+h,g=[];a--;g.push(0));for(y=F,v=O,a=h;--a>=0;){for(r=0,m=_[a]%v,d=_[a]/v|0,u=l,s=a+u;s>a;)f=b[--u]%v,p=b[u]/v|0,c=d*f+p*m,f=m*f+c%v*v+g[s]+r,r=(f/y|0)+(c/v|0)+d*p,g[s--]=f%y;g[s]=r}return r?++o:g.shift(),T(t,g,o)},E.toDigits=function(t,n){var r=new e(this);return t=null!=t&&W(t,1,k,18,"precision")?0|t:null,n=null!=n&&W(n,0,8,18,b)?0|n:L,t?S(r,t,n):r},E.toExponential=function(t,e){return h(this,null!=t&&W(t,0,k,19)?~~t+1:null,e,19)},E.toFixed=function(t,e){return h(this,null!=t&&W(t,0,k,20)?~~t+this.e+1:null,e,20)},E.toFormat=function(t,e){var n=h(this,null!=t&&W(t,0,k,21)?~~t+this.e+1:null,e,21);if(this.c){var r,i=n.split("."),o=+X.groupSize,a=+X.secondaryGroupSize,s=X.groupSeparator,u=i[0],c=i[1],l=this.s<0,f=l?u.slice(1):u,p=f.length;if(a&&(r=o,o=a,a=r,p-=r),o>0&&p>0){for(r=p%o||o,u=f.substr(0,r);p>r;r+=o)u+=s+f.substr(r,o);a>0&&(u+=s+f.slice(r)),l&&(u="-"+u)}n=c?u+X.decimalSeparator+((a=+X.fractionGroupSize)?c.replace(new RegExp("\\d{"+a+"}\\B","g"),"$&"+X.fractionGroupSeparator):c):u}return n},E.toFraction=function(t){var n,r,i,a,s,u,c,l,f,p=z,h=this,m=h.c,d=new e(H),g=r=new e(H),y=c=new e(H);if(null!=t&&(z=!1,u=new e(t),z=p,(!(p=u.isInt())||u.lt(H))&&(z&&D(22,"max denominator "+(p?"out of range":"not an integer"),t),t=!p&&u.c&&S(u,u.e+1,1).gte(H)?u:null)),!m)return h.toString();for(f=o(m),a=d.e=f.length-h.e-1,d.c[0]=N[(s=a%I)<0?I+s:s],t=!t||u.cmp(d)>0?a>0?d:g:u,s=G,G=1/0,u=new e(f),c.c[0]=0;l=R(u,d,0,1),i=r.plus(l.times(y)),1!=i.cmp(t);)r=y,y=i,g=c.plus(l.times(i=g)),c=i,d=u.minus(l.times(i=d)),u=i;return i=R(t.minus(r),y,0,1),c=c.plus(i.times(g)),r=r.plus(i.times(y)),c.s=g.s=h.s,a*=2,n=R(g,y,a,L).minus(h).abs().cmp(R(c,r,a,L).minus(h).abs())<1?[g.toString(),y.toString()]:[c.toString(),r.toString()],G=s,n},E.toNumber=function(){var t=this;return+t||(t.s?0*t.s:0/0)},E.toPower=E.pow=function(t){var n,r,i=v(0>t?-t:+t),o=this;if(!W(t,-B,B,23,"exponent")&&(!isFinite(t)||i>B&&(t/=0)||parseFloat(t)!=t&&!(t=0/0)))return new e(Math.pow(+o,t));for(n=V?y(V/I+2):0,r=new e(H);;){if(i%2){if(r=r.times(o),!r.c)break;n&&r.c.length>n&&(r.c.length=n)}if(i=v(i/2),!i)break;o=o.times(o),n&&o.c&&o.c.length>n&&(o.c.length=n)}return 0>t&&(r=H.div(r)),n?S(r,V,L):r},E.toPrecision=function(t,e){return h(this,null!=t&&W(t,1,k,24,"precision")?0|t:null,e,24)},E.toString=function(t){var e,r=this,i=r.s,a=r.e;return null===a?i?(e="Infinity",0>i&&(e="-"+e)):e="NaN":(e=o(r.c),e=null!=t&&W(t,2,64,25,"base")?n(f(e,a),0|t,10,i):q>=a||a>=U?l(e,a):f(e,a),0>i&&r.c[0]&&(e="-"+e)),e},E.truncated=E.trunc=function(){return S(new e(this),this.e+1,1)},E.valueOf=E.toJSON=function(){return this.toString()},null!=t&&e.config(t),e}function i(t){var e=0|t;return t>0||t===e?e:e-1}function o(t){for(var e,n,r=1,i=t.length,o=t[0]+"";i>r;){for(e=t[r++]+"",n=I-e.length;n--;e="0"+e);o+=e}for(i=o.length;48===o.charCodeAt(--i););return o.slice(0,i+1||1)}function a(t,e){var n,r,i=t.c,o=e.c,a=t.s,s=e.s,u=t.e,c=e.e;if(!a||!s)return null;if(n=i&&!i[0],r=o&&!o[0],n||r)return n?r?0:-s:a; +require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ai;i+=64)n.push(this._outputFormatter(new a(t.dynamicPart().substr(i+64,64))));return n}return this._outputFormatter(t)},u.prototype.sliceParam=function(t,e,n){return"bytes"===this._mode?a.decodeBytes(t,e):s(n)?a.decodeArray(t,e):a.decodeParam(t,e)};var c=function(t){this._types=t};c.prototype._requireType=function(t){var e=this._types.filter(function(e){return e.isType(t)})[0];if(!e)throw Error("invalid solidity type!: "+t);return e},c.prototype._formatInput=function(t,e){return this._requireType(t).formatInput(e,s(t))},c.prototype.encodeParam=function(t,e){return this._formatInput(t,e).encode()},c.prototype.encodeParams=function(t,e){var n=this,r=t.map(function(t,r){return n._formatInput(t,e[r])});return a.encodeList(r)},c.prototype.decodeParam=function(t,e){return this.decodeParams([t],e)[0]},c.prototype.decodeParams=function(t,e){var n=this;return t.map(function(t,r){var o=n._requireType(t),i=o.sliceParam(e,r,t);return o.formatOutput(i,s(t))})};var l=new c([new u({name:"address",match:"strict",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputAddress}),new u({name:"bool",match:"strict",mode:"value",inputFormatter:i.formatInputBool,outputFormatter:i.formatOutputBool}),new u({name:"int",match:"prefix",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputInt}),new u({name:"uint",match:"prefix",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputUInt}),new u({name:"bytes",match:"strict",mode:"bytes",inputFormatter:i.formatInputDynamicBytes,outputFormatter:i.formatOutputDynamicBytes}),new u({name:"bytes",match:"prefix",mode:"value",inputFormatter:i.formatInputBytes,outputFormatter:i.formatOutputBytes}),new u({name:"string",match:"strict",mode:"bytes",inputFormatter:i.formatInputString,outputFormatter:i.formatOutputString}),new u({name:"real",match:"prefix",mode:"value",inputFormatter:i.formatInputReal,outputFormatter:i.formatOutputReal}),new u({name:"ureal",match:"prefix",mode:"value",inputFormatter:i.formatInputReal,outputFormatter:i.formatOutputUReal})]);e.exports=l},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(t,e,n){var r=t("bignumber.js"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./param"),s=function(t){var e=2*i.ETH_PADDING;r.config(i.ETH_BIGNUMBER_ROUNDING_MODE);var n=o.padLeft(o.toTwosComplement(t).round().toString(16),e);return new a(n)},u=function(t){var e=o.padRight(o.toHex(t).substr(2),64);return new a(e)},c=function(t){t=o.toHex(t).substr(2);var e=Math.floor((t.length+63)/64),n=o.padRight(t,64*e),r=Math.floor(t.length/2);return new a(s(r).value+n,32)},l=function(t){var e=o.fromAscii(t).substr(2),n=Math.floor((e.length+63)/64);return e=o.padRight(e,64*n),new a(s(t.length).value+e,32)},f=function(t){var e="000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0");return new a(e)},p=function(t){return s(new r(t).times(new r(2).pow(128)))},h=function(t){return"1"===new r(t.substr(0,1),16).toString(2).substr(0,1)},m=function(t){var e=t.staticPart()||"0";return h(e)?new r(e,16).minus(new r("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new r(e,16)},d=function(t){var e=t.staticPart()||"0";return new r(e,16)},g=function(t){return m(t).dividedBy(new r(2).pow(128))},y=function(t){return d(t).dividedBy(new r(2).pow(128))},v=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t.staticPart()?!0:!1},b=function(t){return"0x"+t.staticPart()},w=function(t){var e=2*new r(t.dynamicPart().slice(0,64),16).toNumber();return"0x"+t.dynamicPart().substr(64,e)},_=function(t){var e=2*new r(t.dynamicPart().slice(0,64),16).toNumber();return o.toAscii(t.dynamicPart().substr(64,e))},x=function(t){var e=t.staticPart();return"0x"+e.slice(e.length-40,e.length)};e.exports={formatInputInt:s,formatInputBytes:u,formatInputDynamicBytes:c,formatInputString:l,formatInputBool:f,formatInputReal:p,formatOutputInt:m,formatOutputUInt:d,formatOutputReal:g,formatOutputUReal:y,formatOutputBool:v,formatOutputBytes:b,formatOutputDynamicBytes:w,formatOutputString:_,formatOutputAddress:x}},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),o=function(t,e){this.value=t||"",this.offset=e};o.prototype.dynamicPartLength=function(){return this.dynamicPart().length/2},o.prototype.withOffset=function(t){return new o(this.value,t)},o.prototype.combine=function(t){return new o(this.value+t.value)},o.prototype.isDynamic=function(){return this.value.length>64||void 0!==this.offset},o.prototype.offsetAsBytes=function(){return this.isDynamic()?r.padLeft(r.toTwosComplement(this.offset).toString(16),64):""},o.prototype.staticPart=function(){return this.isDynamic()?this.offsetAsBytes():this.value},o.prototype.dynamicPart=function(){return this.isDynamic()?this.value:""},o.prototype.encode=function(){return this.staticPart()+this.dynamicPart()},o.encodeList=function(t){var e=32*t.length,n=t.map(function(t){if(!t.isDynamic())return t;var n=e;return e+=t.dynamicPartLength(),t.withOffset(n)});return n.reduce(function(t,e){return t+e.dynamicPart()},n.reduce(function(t,e){return t+e.staticPart()},""))},o.decodeParam=function(t,e){return e=e||0,new o(t.substr(64*e,64))};var i=function(t,e){return parseInt("0x"+t.substr(64*e,64))};o.decodeBytes=function(t,e){e=e||0;var n=i(t,e),r=parseInt("0x"+t.substr(2*n,64));return r=Math.floor((r+31)/32),new o(t.substr(2*n,64*(1+r)),0)},o.decodeArray=function(t,e){e=e||0;var n=i(t,e),r=parseInt("0x"+t.substr(2*n,64));return new o(t.substr(2*n,64*(r+1)),0)},e.exports=o},{"../utils/utils":7}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e,n){var r=t("bignumber.js"),o=["wei","kwei","Mwei","Gwei","szabo","finney","femtoether","picoether","nanoether","microether","milliether","nano","micro","milli","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:o,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:r.ROUND_DOWN},ETH_POLLING_TIMEOUT:500,defaultBlock:"latest",defaultAccount:void 0}},{"bignumber.js":"bignumber.js"}],6:[function(t,e,n){var r=t("./utils"),o=t("crypto-js/sha3");e.exports=function(t,e){return"0x"!==t.substr(0,2)||e||(console.warn("requirement of using web3.fromAscii before sha3 is deprecated"),console.warn("new usage: 'web3.sha3(\"hello\")'"),console.warn("see https://github.com/ethereum/web3.js/pull/205"),console.warn("if you need to hash hex value, you can do 'sha3(\"0xfff\", true)'"),t=r.toAscii(t)),o(t,{outputLength:256}).toString()}},{"./utils":7,"crypto-js/sha3":34}],7:[function(t,e,n){var r=t("bignumber.js"),o={wei:"1",kwei:"1000",ada:"1000",femtoether:"1000",mwei:"1000000",babbage:"1000000",picoether:"1000000",gwei:"1000000000",shannon:"1000000000",nanoether:"1000000000",nano:"1000000000",szabo:"1000000000000",microether:"1000000000000",micro:"1000000000000",finney:"1000000000000000",milliether:"1000000000000000",milli:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},i=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t,e,n){return t+new Array(e-t.length+1).join(n?n:"0")},s=function(t){var e="",n=0,r=t.length;for("0x"===t.substring(0,2)&&(n=2);r>n;n+=2){var o=parseInt(t.substr(n,2),16);e+=String.fromCharCode(o)}return e},u=function(t){for(var e="",n=0;n50){if(a.stopWatching(),i=!0,!n)throw new Error("Contract transaction couldn't be found after 50 blocks");n(new Error("Contract transaction couldn't be found after 50 blocks"))}else r.eth.getTransactionReceipt(t.transactionHash,function(o,s){s&&!i&&r.eth.getCode(s.contractAddress,function(r,o){if(!i)if(a.stopWatching(),i=!0,o.length>2)t.address=s.contractAddress,l(t,e),f(t,e),n&&n(null,t);else{if(!n)throw new Error("The contract code couldn't be stored, please check your gas amount.");n(new Error("The contract code couldn't be stored, please check your gas amount."))}})})})},m=function(t){this.abi=t};m.prototype["new"]=function(){var t,e=this,n=new d(this.abi),i={},a=Array.prototype.slice.call(arguments);o.isFunction(a[a.length-1])&&(t=a.pop());var s=a[a.length-1];o.isObject(s)&&!o.isArray(s)&&(i=a.pop());var u=c(this.abi,a);if(i.data+=u,t)r.eth.sendTransaction(i,function(r,o){r?t(r):(n.transactionHash=o,t(null,n),h(n,e.abi,t))});else{var l=r.eth.sendTransaction(i);n.transactionHash=l,h(n,e.abi)}return n},m.prototype.at=function(t,e){var n=new d(this.abi,t);return l(n,this.abi),f(n,this.abi),e&&e(null,n),n};var d=function(t,e){this.address=e};e.exports=p},{"../solidity/coder":1,"../utils/utils":7,"../web3":9,"./allevents":10,"./event":16,"./function":19}],13:[function(t,e,n){var r=t("./method"),o=new r({name:"putString",call:"db_putString",params:3}),i=new r({name:"getString",call:"db_getString",params:2}),a=new r({name:"putHex",call:"db_putHex",params:3}),s=new r({name:"getHex",call:"db_getHex",params:2}),u=[o,i,a,s];e.exports={methods:u}},{"./method":24}],14:[function(t,e,n){e.exports={InvalidNumberOfParams:function(){return new Error("Invalid number of input parameters")},InvalidConnection:function(t){return new Error("CONNECTION ERROR: Couldn't connect to node "+t+", is it running?")},InvalidProvider:function(){return new Error("Providor not set or invalid")},InvalidResponse:function(t){var e=t&&t.error&&t.error.message?t.error.message:"Invalid JSON RPC response: "+t;return new Error(e)}}},{}],15:[function(t,e,n){"use strict";var r=t("./formatters"),o=t("../utils/utils"),i=t("./method"),a=t("./property"),s=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getBlockByHash":"eth_getBlockByNumber"},u=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getTransactionByBlockHashAndIndex":"eth_getTransactionByBlockNumberAndIndex"},c=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getUncleByBlockHashAndIndex":"eth_getUncleByBlockNumberAndIndex"},l=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getBlockTransactionCountByHash":"eth_getBlockTransactionCountByNumber"},f=function(t){return o.isString(t[0])&&0===t[0].indexOf("0x")?"eth_getUncleCountByBlockHash":"eth_getUncleCountByBlockNumber"},p=new i({name:"getBalance",call:"eth_getBalance",params:2,inputFormatter:[o.toAddress,r.inputDefaultBlockNumberFormatter],outputFormatter:r.outputBigNumberFormatter}),h=new i({name:"getStorageAt",call:"eth_getStorageAt",params:3,inputFormatter:[null,o.toHex,r.inputDefaultBlockNumberFormatter]}),m=new i({name:"getCode",call:"eth_getCode",params:2,inputFormatter:[o.toAddress,r.inputDefaultBlockNumberFormatter]}),d=new i({name:"getBlock",call:s,params:2,inputFormatter:[r.inputBlockNumberFormatter,function(t){return!!t}],outputFormatter:r.outputBlockFormatter}),g=new i({name:"getUncle",call:c,params:2,inputFormatter:[r.inputBlockNumberFormatter,o.toHex],outputFormatter:r.outputBlockFormatter}),y=new i({name:"getCompilers",call:"eth_getCompilers",params:0}),v=new i({name:"getBlockTransactionCount",call:l,params:1,inputFormatter:[r.inputBlockNumberFormatter],outputFormatter:o.toDecimal}),b=new i({name:"getBlockUncleCount",call:f,params:1,inputFormatter:[r.inputBlockNumberFormatter],outputFormatter:o.toDecimal}),w=new i({name:"getTransaction",call:"eth_getTransactionByHash",params:1,outputFormatter:r.outputTransactionFormatter}),_=new i({name:"getTransactionFromBlock",call:u,params:2,inputFormatter:[r.inputBlockNumberFormatter,o.toHex],outputFormatter:r.outputTransactionFormatter}),x=new i({name:"getTransactionReceipt",call:"eth_getTransactionReceipt",params:1,outputFormatter:r.outputTransactionReceiptFormatter}),F=new i({name:"getTransactionCount",call:"eth_getTransactionCount",params:2,inputFormatter:[null,r.inputDefaultBlockNumberFormatter],outputFormatter:o.toDecimal}),I=new i({name:"sendRawTransaction",call:"eth_sendRawTransaction",params:1,inputFormatter:[null]}),k=new i({name:"sendTransaction",call:"eth_sendTransaction",params:1,inputFormatter:[r.inputTransactionFormatter]}),B=new i({name:"call",call:"eth_call",params:2,inputFormatter:[r.inputTransactionFormatter,r.inputDefaultBlockNumberFormatter]}),N=new i({name:"estimateGas",call:"eth_estimateGas",params:1,inputFormatter:[r.inputTransactionFormatter],outputFormatter:o.toDecimal}),O=new i({name:"compile.solidity",call:"eth_compileSolidity",params:1}),T=new i({name:"compile.lll",call:"eth_compileLLL",params:1}),A=new i({name:"compile.serpent",call:"eth_compileSerpent",params:1}),P=new i({name:"submitWork",call:"eth_submitWork",params:3}),C=new i({name:"getWork",call:"eth_getWork",params:0}),S=[p,h,m,d,g,y,v,b,w,_,x,F,B,N,I,k,O,T,A,P,C],D=[new a({name:"coinbase",getter:"eth_coinbase"}),new a({name:"mining",getter:"eth_mining"}),new a({name:"hashrate",getter:"eth_hashrate",outputFormatter:o.toDecimal}),new a({name:"gasPrice",getter:"eth_gasPrice",outputFormatter:r.outputBigNumberFormatter}),new a({name:"accounts",getter:"eth_accounts"}),new a({name:"blockNumber",getter:"eth_blockNumber",outputFormatter:o.toDecimal})];e.exports={methods:S,properties:D}},{"../utils/utils":7,"./formatters":18,"./method":24,"./property":27}],16:[function(t,e,n){var r=t("../utils/utils"),o=t("../solidity/coder"),i=t("./formatters"),a=t("../utils/sha3"),s=t("./filter"),u=t("./watches"),c=function(t,e){this._params=t.inputs,this._name=r.transformToFullName(t),this._address=e,this._anonymous=t.anonymous};c.prototype.types=function(t){return this._params.filter(function(e){return e.indexed===t}).map(function(t){return t.type})},c.prototype.displayName=function(){return r.extractDisplayName(this._name)},c.prototype.typeName=function(){return r.extractTypeName(this._name)},c.prototype.signature=function(){return a(this._name)},c.prototype.encode=function(t,e){t=t||{},e=e||{};var n={};["fromBlock","toBlock"].filter(function(t){return void 0!==e[t]}).forEach(function(t){n[t]=i.inputBlockNumberFormatter(e[t])}),n.topics=[],n.address=this._address,this._anonymous||n.topics.push("0x"+this.signature());var a=this._params.filter(function(t){return t.indexed===!0}).map(function(e){var n=t[e.name];return void 0===n||null===n?null:r.isArray(n)?n.map(function(t){return"0x"+o.encodeParam(e.type,t)}):"0x"+o.encodeParam(e.type,n)});return n.topics=n.topics.concat(a),n},c.prototype.decode=function(t){t.data=t.data||"",t.topics=t.topics||[];var e=this._anonymous?t.topics:t.topics.slice(1),n=e.map(function(t){return t.slice(2)}).join(""),r=o.decodeParams(this.types(!0),n),a=t.data.slice(2),s=o.decodeParams(this.types(!1),a),u=i.outputLogFormatter(t);return u.event=this.displayName(),u.address=t.address,u.args=this._params.reduce(function(t,e){return t[e.name]=e.indexed?r.shift():s.shift(),t},{}),delete u.data,delete u.topics,u},c.prototype.execute=function(t,e,n){r.isFunction(arguments[arguments.length-1])&&(n=arguments[arguments.length-1],2===arguments.length&&(e=null),1===arguments.length&&(e=null,t={}));var o=this.encode(t,e),i=this.decode.bind(this);return new s(o,u.eth(),i,n)},c.prototype.attachToContract=function(t){var e=this.execute.bind(this),n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=this.execute.bind(this,t)},e.exports=c},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"./filter":17,"./formatters":18,"./watches":31}],17:[function(t,e,n){var r=t("./requestmanager"),o=t("./formatters"),i=t("../utils/utils"),a=function(t){return null===t||"undefined"==typeof t?null:(t=String(t),0===t.indexOf("0x")?t:i.fromAscii(t))},s=function(t){return i.isString(t)?t:(t=t||{},t.topics=t.topics||[],t.topics=t.topics.map(function(t){return i.isArray(t)?t.map(a):a(t)}),{topics:t.topics,to:t.to,address:t.address,fromBlock:o.inputBlockNumberFormatter(t.fromBlock),toBlock:o.inputBlockNumberFormatter(t.toBlock)})},u=function(t,e){i.isString(t.options)||t.get(function(t,n){t&&e(t),i.isArray(n)&&n.forEach(function(t){e(null,t)})})},c=function(t){var e=function(e,n){return e?t.callbacks.forEach(function(t){t(e)}):void n.forEach(function(e){e=t.formatter?t.formatter(e):e,t.callbacks.forEach(function(t){t(null,e)})})};r.getInstance().startPolling({method:t.implementation.poll.call,params:[t.filterId]},t.filterId,e,t.stopWatching.bind(t))},l=function(t,e,n,r){var o=this,i={};e.forEach(function(t){t.attachToObject(i)}),this.options=s(t),this.implementation=i,this.filterId=null,this.callbacks=[],this.pollFilters=[],this.formatter=n,this.implementation.newFilter(this.options,function(t,e){if(t)o.callbacks.forEach(function(e){e(t)});else if(o.filterId=e,o.callbacks.forEach(function(t){u(o,t)}),o.callbacks.length>0&&c(o),r)return o.watch(r)})};l.prototype.watch=function(t){return this.callbacks.push(t),this.filterId&&(u(this,t),c(this)),this},l.prototype.stopWatching=function(){r.getInstance().stopPolling(this.filterId),this.implementation.uninstallFilter(this.filterId,function(){}),this.callbacks=[]},l.prototype.get=function(t){var e=this;if(!i.isFunction(t)){var n=this.implementation.getLogs(this.filterId);return n.map(function(t){return e.formatter?e.formatter(t):t})}return this.implementation.getLogs(this.filterId,function(n,r){n?t(n):t(null,r.map(function(t){return e.formatter?e.formatter(t):t}))}),this},e.exports=l},{"../utils/utils":7,"./formatters":18,"./requestmanager":28}],18:[function(t,e,n){var r=t("../utils/utils"),o=t("../utils/config"),i=function(t){return r.toBigNumber(t)},a=function(t){return"latest"===t||"pending"===t||"earliest"===t},s=function(t){return void 0===t?o.defaultBlock:u(t)},u=function(t){return void 0===t?void 0:a(t)?t:r.toHex(t)},c=function(t){return t.from=t.from||o.defaultAccount,t.code&&(t.data=t.code,delete t.code),["gasPrice","gas","value","nonce"].filter(function(e){return void 0!==t[e]}).forEach(function(e){t[e]=r.fromDecimal(t[e])}),t},l=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),t.nonce=r.toDecimal(t.nonce),t.gas=r.toDecimal(t.gas),t.gasPrice=r.toBigNumber(t.gasPrice),t.value=r.toBigNumber(t.value),t},f=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),t.cumulativeGasUsed=r.toDecimal(t.cumulativeGasUsed),t.gasUsed=r.toDecimal(t.gasUsed),r.isArray(t.logs)&&(t.logs=t.logs.map(function(t){return h(t)})),t},p=function(t){return t.gasLimit=r.toDecimal(t.gasLimit),t.gasUsed=r.toDecimal(t.gasUsed),t.size=r.toDecimal(t.size),t.timestamp=r.toDecimal(t.timestamp),null!==t.number&&(t.number=r.toDecimal(t.number)),t.difficulty=r.toBigNumber(t.difficulty),t.totalDifficulty=r.toBigNumber(t.totalDifficulty),r.isArray(t.transactions)&&t.transactions.forEach(function(t){return r.isString(t)?void 0:l(t)}),t},h=function(t){return null!==t.blockNumber&&(t.blockNumber=r.toDecimal(t.blockNumber)),null!==t.transactionIndex&&(t.transactionIndex=r.toDecimal(t.transactionIndex)),null!==t.logIndex&&(t.logIndex=r.toDecimal(t.logIndex)),t},m=function(t){return t.payload=r.toHex(t.payload),t.ttl=r.fromDecimal(t.ttl),t.workToProve=r.fromDecimal(t.workToProve),t.priority=r.fromDecimal(t.priority),r.isArray(t.topics)||(t.topics=t.topics?[t.topics]:[]),t.topics=t.topics.map(function(t){return r.fromAscii(t)}),t},d=function(t){return t.expiry=r.toDecimal(t.expiry),t.sent=r.toDecimal(t.sent),t.ttl=r.toDecimal(t.ttl),t.workProved=r.toDecimal(t.workProved),t.payloadRaw=t.payload,t.payload=r.toAscii(t.payload),r.isJson(t.payload)&&(t.payload=JSON.parse(t.payload)),t.topics||(t.topics=[]),t.topics=t.topics.map(function(t){return r.toAscii(t)}),t};e.exports={inputDefaultBlockNumberFormatter:s,inputBlockNumberFormatter:u,inputTransactionFormatter:c,inputPostFormatter:m,outputBigNumberFormatter:i,outputTransactionFormatter:l,outputTransactionReceiptFormatter:f,outputBlockFormatter:p,outputLogFormatter:h,outputPostFormatter:d}},{"../utils/config":5,"../utils/utils":7}],19:[function(t,e,n){var r=t("../web3"),o=t("../solidity/coder"),i=t("../utils/utils"),a=t("./formatters"),s=t("../utils/sha3"),u=function(t,e){this._inputTypes=t.inputs.map(function(t){return t.type}),this._outputTypes=t.outputs.map(function(t){return t.type}),this._constant=t.constant,this._name=i.transformToFullName(t),this._address=e};u.prototype.extractCallback=function(t){return i.isFunction(t[t.length-1])?t.pop():void 0},u.prototype.extractDefaultBlock=function(t){return t.length>this._inputTypes.length&&!i.isObject(t[t.length-1])?a.inputDefaultBlockNumberFormatter(t.pop()):void 0},u.prototype.toPayload=function(t){var e={};return t.length>this._inputTypes.length&&i.isObject(t[t.length-1])&&(e=t[t.length-1]),e.to=this._address,e.data="0x"+this.signature()+o.encodeParams(this._inputTypes,t),e},u.prototype.signature=function(){return s(this._name).slice(0,8)},u.prototype.unpackOutput=function(t){if(t){t=t.length>=2?t.slice(2):t;var e=o.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},u.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.extractDefaultBlock(t),o=this.toPayload(t);if(!e){var i=r.eth.call(o,n);return this.unpackOutput(i)}var a=this;r.eth.call(o,n,function(t,n){e(t,a.unpackOutput(n))})},u.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):r.eth.sendTransaction(n)},u.prototype.estimateGas=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.estimateGas(n,e):r.eth.estimateGas(n)},u.prototype.displayName=function(){return i.extractDisplayName(this._name)},u.prototype.typeName=function(){return i.extractTypeName(this._name)},u.prototype.request=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t),r=this.unpackOutput.bind(this);return{method:this._constant?"eth_call":"eth_sendTransaction",callback:e,params:[n],format:r}},u.prototype.execute=function(){var t=!this._constant;return t?this.sendTransaction.apply(this,Array.prototype.slice.call(arguments)):this.call.apply(this,Array.prototype.slice.call(arguments))},u.prototype.attachToContract=function(t){var e=this.execute.bind(this);e.request=this.request.bind(this),e.call=this.call.bind(this),e.sendTransaction=this.sendTransaction.bind(this),e.estimateGas=this.estimateGas.bind(this);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=u},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":18}],20:[function(t,e,n){"use strict";var r="undefined"!=typeof window&&window.XMLHttpRequest?window.XMLHttpRequest:t("xmlhttprequest").XMLHttpRequest,o=t("./errors"),i=function(t){this.host=t||"http://localhost:8545"};i.prototype.isConnected=function(){var t=new r;t.open("POST",this.host,!1),t.setRequestHeader("Content-type","application/json");try{return t.send(JSON.stringify({id:9999999999,jsonrpc:"2.0",method:"net_listening",params:[]})),!0}catch(e){return!1; -if(a!=s)return a;if(n=0>a,r=u==c,!i||!o)return r?0:!i^n?1:-1;if(!r)return u>c^n?1:-1;for(s=(u=i.length)<(c=o.length)?u:c,a=0;s>a;a++)if(i[a]!=o[a])return i[a]>o[a]^n?1:-1;return u==c?0:u>c^n?1:-1}function s(t,e,n){return(t=p(t))>=e&&n>=t}function u(t){return"[object Array]"==Object.prototype.toString.call(t)}function c(t,e,n){for(var r,i,o=[0],a=0,s=t.length;s>a;){for(i=o.length;i--;o[i]*=e);for(o[r=0]+=x.indexOf(t.charAt(a++));rn-1&&(null==o[r+1]&&(o[r+1]=0),o[r+1]+=o[r]/n|0,o[r]%=n)}return o.reverse()}function l(t,e){return(t.length>1?t.charAt(0)+"."+t.slice(1):t)+(0>e?"e":"e+")+e}function f(t,e){var n,r;if(0>e){for(r="0.";++e;r+="0");t=r+t}else if(n=t.length,++e>n){for(r="0",e-=n;--e;r+="0");t+=r}else n>e&&(t=t.slice(0,e)+"."+t.slice(e));return t}function p(t){return t=parseFloat(t),0>t?y(t):v(t)}var h,m,d,g=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,y=Math.ceil,v=Math.floor,w=" not a boolean or binary digit",b="rounding mode",_="number type has more than 15 significant digits",x="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",F=1e14,I=14,B=9007199254740991,N=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],O=1e7,k=1e9;if(h=r(),"function"==typeof define&&define.amd)define(function(){return h});else if("undefined"!=typeof e&&e.exports){if(e.exports=h,!m)try{m=t("crypto")}catch(A){}}else n.BigNumber=h}(this)},{crypto:32}],web3:[function(t,e,n){var r=t("./lib/web3");r.providers.HttpProvider=t("./lib/web3/httpprovider"),r.providers.QtSyncProvider=t("./lib/web3/qtsync"),r.eth.contract=t("./lib/web3/contract"),r.eth.namereg=t("./lib/web3/namereg"),r.eth.sendIBANTransaction=t("./lib/web3/transfer"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/namereg":24,"./lib/web3/qtsync":27,"./lib/web3/transfer":30}]},{},["web3"]); \ No newline at end of file +}},i.prototype.send=function(t){var e=new r;e.open("POST",this.host,!1),e.setRequestHeader("Content-type","application/json");try{e.send(JSON.stringify(t))}catch(n){throw o.InvalidConnection(this.host)}var i=e.responseText;try{i=JSON.parse(i)}catch(a){throw o.InvalidResponse(e.responseText)}return i},i.prototype.sendAsync=function(t,e){var n=new r;n.onreadystatechange=function(){if(4===n.readyState){var t=n.responseText,r=null;try{t=JSON.parse(t)}catch(i){r=o.InvalidResponse(n.responseText)}e(r,t)}},n.open("POST",this.host,!0),n.setRequestHeader("Content-type","application/json");try{n.send(JSON.stringify(t))}catch(i){e(o.InvalidConnection(this.host))}},e.exports=i},{"./errors":14,xmlhttprequest:4}],21:[function(t,e,n){var r=t("../utils/utils"),o=function(t){this._iban=t};o.prototype.isValid=function(){return r.isIBAN(this._iban)},o.prototype.isDirect=function(){return 34===this._iban.length},o.prototype.isIndirect=function(){return 20===this._iban.length},o.prototype.checksum=function(){return this._iban.substr(2,2)},o.prototype.institution=function(){return this.isIndirect()?this._iban.substr(7,4):""},o.prototype.client=function(){return this.isIndirect()?this._iban.substr(11):""},o.prototype.address=function(){return this.isDirect()?this._iban.substr(4):""},e.exports=o},{"../utils/utils":7}],22:[function(t,e,n){"use strict";var r=t("../utils/utils"),o=t("./errors"),i='{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}',a=function(e,n){var o=this;this.responseCallbacks={},this.path=e,n=n||t("net"),this.connection=n.connect({path:this.path}),this.connection.on("error",function(t){console.error("IPC Connection Error",t),o._timeout()}),this.connection.on("end",function(){o._timeout()}),this.connection.on("data",function(t){o._parseResponse(t.toString()).forEach(function(t){var e=null;r.isArray(t)?t.forEach(function(t){o.responseCallbacks[t.id]&&(e=t.id)}):e=t.id,o.responseCallbacks[e]&&(o.responseCallbacks[e](null,t),delete o.responseCallbacks[e])})})};a.prototype._parseResponse=function(t){var e=this,n=[],r=t.replace(/\}\{/g,"}|--|{").replace(/\}\]\[\{/g,"}]|--|[{").replace(/\}\[\{/g,"}|--|[{").replace(/\}\]\{/g,"}]|--|{").split("|--|");return r.forEach(function(t){e.lastChunk&&(t=e.lastChunk+t);var r=null;try{r=JSON.parse(t)}catch(i){return e.lastChunk=t,clearTimeout(e.lastChunkTimeout),void(e.lastChunkTimeout=setTimeout(function(){throw e.timeout(),o.InvalidResponse(t)},15e3))}clearTimeout(e.lastChunkTimeout),e.lastChunk=null,r&&n.push(r)}),n},a.prototype._addResponseCallback=function(t,e){var n=t.id||t[0].id,r=t.method||t[0].method;this.responseCallbacks[n]=e,this.responseCallbacks[n].method=r},a.prototype._timeout=function(){for(var t in this.responseCallbacks)this.responseCallbacks.hasOwnProperty(t)&&(this.responseCallbacks[t](i.replace("__id__",t).replace("__method__",this.responseCallbacks[t].method)),delete this.responseCallbacks[t])},a.prototype.isConnected=function(){var t=this;return t.connection.writable||t.connection.connect({path:t.path}),!!this.connection.writable},a.prototype.send=function(t){if(this.connection.writeSync){var e;this.connection.writable||this.connection.connect({path:this.path});var n=this.connection.writeSync(JSON.stringify(t));try{e=JSON.parse(n)}catch(r){throw o.InvalidResponse(n)}return e}throw new Error('You tried to send "'+t.method+'" synchronously. Synchronous requests are not supported by the IPC provider.')},a.prototype.sendAsync=function(t,e){this.connection.writable||this.connection.connect({path:this.path}),this.connection.write(JSON.stringify(t)),this._addResponseCallback(t,e)},e.exports=a},{"../utils/utils":7,"./errors":14,net:32}],23:[function(t,e,n){var r=function(){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,void(this.messageId=1))};r.getInstance=function(){var t=new r;return t},r.prototype.toPayload=function(t,e){return t||console.error("jsonrpc method should be specified!"),{jsonrpc:"2.0",method:t,params:e||[],id:this.messageId++}},r.prototype.isValidResponse=function(t){return!!t&&!t.error&&"2.0"===t.jsonrpc&&"number"==typeof t.id&&void 0!==t.result},r.prototype.toBatchPayload=function(t){var e=this;return t.map(function(t){return e.toPayload(t.method,t.params)})},e.exports=r},{}],24:[function(t,e,n){var r=t("./requestmanager"),o=t("../utils/utils"),i=t("./errors"),a=function(t){this.name=t.name,this.call=t.call,this.params=t.params||0,this.inputFormatter=t.inputFormatter,this.outputFormatter=t.outputFormatter};a.prototype.getCall=function(t){return o.isFunction(this.call)?this.call(t):this.call},a.prototype.extractCallback=function(t){return o.isFunction(t[t.length-1])?t.pop():void 0},a.prototype.validateArgs=function(t){if(t.length!==this.params)throw i.InvalidNumberOfParams()},a.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter.map(function(e,n){return e?e(t[n]):t[n]}):t},a.prototype.formatOutput=function(t){return this.outputFormatter&&t?this.outputFormatter(t):t},a.prototype.attachToObject=function(t){var e=this.send.bind(this);e.request=this.request.bind(this),e.call=this.call;var n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},a.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},a.prototype.request=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));return t.format=this.formatOutput.bind(this),t},a.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return r.getInstance().sendAsync(t,function(n,r){t.callback(n,e.formatOutput(r))})}return this.formatOutput(r.getInstance().send(t))},e.exports=a},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],25:[function(t,e,n){var r=t("./contract"),o="0xc6d9d2cd449a754c494264e1809c50e34d64562b",i=[{constant:!0,inputs:[{name:"_owner",type:"address"}],name:"name",outputs:[{name:"o_name",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"owner",outputs:[{name:"",type:"address"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"content",outputs:[{name:"",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"addr",outputs:[{name:"",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"reserve",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"subRegistrar",outputs:[{name:"o_subRegistrar",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_newOwner",type:"address"}],name:"transfer",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_registrar",type:"address"}],name:"setSubRegistrar",outputs:[],type:"function"},{constant:!1,inputs:[],name:"Registrar",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_a",type:"address"},{name:"_primary",type:"bool"}],name:"setAddress",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_content",type:"bytes32"}],name:"setContent",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"disown",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"register",outputs:[{name:"",type:"address"}],type:"function"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"}],name:"Changed",type:"event"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"},{indexed:!0,name:"addr",type:"address"}],name:"PrimaryChanged",type:"event"}];e.exports=r(i).at(o)},{"./contract":12}],26:[function(t,e,n){var r=t("../utils/utils"),o=t("./property"),i=[],a=[new o({name:"listening",getter:"net_listening"}),new o({name:"peerCount",getter:"net_peerCount",outputFormatter:r.toDecimal})];e.exports={methods:i,properties:a}},{"../utils/utils":7,"./property":27}],27:[function(t,e,n){var r=t("./requestmanager"),o=t("../utils/utils"),i=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};i.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},i.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},i.prototype.extractCallback=function(t){return o.isFunction(t[t.length-1])?t.pop():void 0},i.prototype.attachToObject=function(t){var e={get:this.get.bind(this)},n=this.name.split("."),r=n[0];n.length>1&&(t[n[0]]=t[n[0]]||{},t=t[n[0]],r=n[1]),Object.defineProperty(t,r,e);var o=function(t,e){return t+e.charAt(0).toUpperCase()+e.slice(1)},i=this.getAsync.bind(this);i.request=this.request.bind(this),t[o("get",r)]=i},i.prototype.get=function(){return this.formatOutput(r.getInstance().send({method:this.getter}))},i.prototype.getAsync=function(t){var e=this;r.getInstance().sendAsync({method:this.getter},function(n,r){return n?t(n):void t(n,e.formatOutput(r))})},i.prototype.request=function(){var t={method:this.getter,params:[],callback:this.extractCallback(Array.prototype.slice.call(arguments))};return t.format=this.formatOutput.bind(this),t},e.exports=i},{"../utils/utils":7,"./requestmanager":28}],28:[function(t,e,n){var r=t("./jsonrpc"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./errors"),s=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls={},this.timeout=null,void(this.isPolling=!1))};s.getInstance=function(){var t=new s;return t},s.prototype.send=function(t){if(!this.provider)return console.error(a.InvalidProvider()),null;var e=r.getInstance().toPayload(t.method,t.params),n=this.provider.send(e);if(!r.getInstance().isValidResponse(n))throw a.InvalidResponse(n);return n.result},s.prototype.sendAsync=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(n,function(t,n){return t?e(t):r.getInstance().isValidResponse(n)?void e(null,n.result):e(a.InvalidResponse(n))})},s.prototype.sendBatch=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toBatchPayload(t);this.provider.sendAsync(n,function(t,n){return t?e(t):o.isArray(n)?void e(t,n):e(a.InvalidResponse(n))})},s.prototype.setProvider=function(t){this.provider=t,this.provider&&!this.isPolling&&(this.poll(),this.isPolling=!0)},s.prototype.startPolling=function(t,e,n,r){this.polls["poll_"+e]={data:t,id:e,callback:n,uninstall:r}},s.prototype.stopPolling=function(t){delete this.polls["poll_"+t]},s.prototype.reset=function(){for(var t in this.polls)this.polls[t].uninstall();this.polls={},this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},s.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),i.ETH_POLLING_TIMEOUT),0!==Object.keys(this.polls).length){if(!this.provider)return void console.error(a.InvalidProvider());var t=[],e=[];for(var n in this.polls)t.push(this.polls[n].data),e.push(n);if(0!==t.length){var s=r.getInstance().toBatchPayload(t),u=this;this.provider.sendAsync(s,function(t,n){if(!t){if(!o.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){var r=e[n];return u.polls[r]?(t.callback=u.polls[r].callback,t):!1}).filter(function(t){return!!t}).filter(function(t){var e=r.getInstance().isValidResponse(t);return e||t.callback(a.InvalidResponse(t)),e}).filter(function(t){return o.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}}},e.exports=s},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":23}],29:[function(t,e,n){var r=t("./method"),o=t("./formatters"),i=new r({name:"post",call:"shh_post",params:1,inputFormatter:[o.inputPostFormatter]}),a=new r({name:"newIdentity",call:"shh_newIdentity",params:0}),s=new r({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new r({name:"newGroup",call:"shh_newGroup",params:0}),c=new r({name:"addToGroup",call:"shh_addToGroup",params:0}),l=[i,a,s,u,c];e.exports={methods:l}},{"./formatters":18,"./method":24}],30:[function(t,e,n){var r=t("../web3"),o=t("./icap"),i=t("./namereg"),a=t("./contract"),s=function(t,e,n,r){var a=new o(e);if(!a.isValid())throw new Error("invalid iban address");if(a.isDirect())return u(t,a.address(),n,r);if(!r){var s=i.addr(a.institution());return c(t,s,n,a.client())}i.addr(a.insitution(),function(e,o){return c(t,o,n,a.client(),r)})},u=function(t,e,n,o){return r.eth.sendTransaction({address:e,from:t,value:n},o)},c=function(t,e,n,r,o){var i=[{constant:!1,inputs:[{name:"name",type:"bytes32"}],name:"deposit",outputs:[],type:"function"}];return a(i).at(e).deposit(r,{from:t,value:n},o)};e.exports=s},{"../web3":9,"./contract":12,"./icap":21,"./namereg":25}],31:[function(t,e,n){var r=t("./method"),o=function(){var t=function(t){var e=t[0];switch(e){case"latest":return t.shift(),this.params=0,"eth_newBlockFilter";case"pending":return t.shift(),this.params=0,"eth_newPendingTransactionFilter";default:return"eth_newFilter"}},e=new r({name:"newFilter",call:t,params:1}),n=new r({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),o=new r({name:"getLogs",call:"eth_getFilterLogs",params:1}),i=new r({name:"poll",call:"eth_getFilterChanges",params:1});return[e,n,o,i]},i=function(){var t=new r({name:"newFilter",call:"shh_newFilter",params:1}),e=new r({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),n=new r({name:"getLogs",call:"shh_getMessages",params:1}),o=new r({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,n,o]};e.exports={eth:o,shh:i}},{"./method":24}],32:[function(t,e,n){},{}],33:[function(t,e,n){!function(t,r){"object"==typeof n?e.exports=n=r():"function"==typeof define&&define.amd?define([],r):t.CryptoJS=r()}(this,function(){var t=t||function(t,e){var n={},r=n.lib={},o=r.Base=function(){function t(){}return{extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),i=r.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:4*t.length},toString:function(t){return(t||s).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes,o=t.sigBytes;if(this.clamp(),r%4)for(var i=0;o>i;i++){var a=n[i>>>2]>>>24-i%4*8&255;e[r+i>>>2]|=a<<24-(r+i)%4*8}else for(var i=0;o>i;i+=4)e[r+i>>>2]=n[i>>>2];return this.sigBytes+=o,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=o.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n,r=[],o=function(e){var e=e,n=987654321,r=4294967295;return function(){n=36969*(65535&n)+(n>>16)&r,e=18e3*(65535&e)+(e>>16)&r;var o=(n<<16)+e&r;return o/=4294967296,o+=.5,o*(t.random()>.5?1:-1)}},a=0;e>a;a+=4){var s=o(4294967296*(n||t.random()));n=987654071*s(),r.push(4294967296*s()|0)}return new i.init(r,e)}}),a=n.enc={},s=a.Hex={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push((i>>>4).toString(16)),r.push((15&i).toString(16))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r+=2)n[r>>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new i.init(n,e/2)}},u=a.Latin1={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push(String.fromCharCode(i))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r++)n[r>>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new i.init(n,e)}},c=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},l=r.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new i.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=c.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,o=n.sigBytes,a=this.blockSize,s=4*a,u=o/s;u=e?t.ceil(u):t.max((0|u)-this._minBufferSize,0);var c=u*a,l=t.min(4*c,o);if(c){for(var f=0;c>f;f+=a)this._doProcessBlock(r,f);var p=r.splice(0,c);n.sigBytes-=l}return new i.init(p,l)},clone:function(){var t=o.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),f=(r.Hasher=l.extend({cfg:o.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){l.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},blockSize:16,_createHelper:function(t){return function(e,n){return new t.init(n).finalize(e)}},_createHmacHelper:function(t){return function(e,n){return new f.HMAC.init(t,n).finalize(e)}}}),n.algo={});return n}(Math);return t})},{}],34:[function(t,e,n){!function(r,o,i){"object"==typeof n?e.exports=n=o(t("./core"),t("./x64-core")):"function"==typeof define&&define.amd?define(["./core","./x64-core"],o):o(r.CryptoJS)}(this,function(t){return function(e){var n=t,r=n.lib,o=r.WordArray,i=r.Hasher,a=n.x64,s=a.Word,u=n.algo,c=[],l=[],f=[];!function(){for(var t=1,e=0,n=0;24>n;n++){c[t+5*e]=(n+1)*(n+2)/2%64;var r=e%5,o=(2*t+3*e)%5;t=r,e=o}for(var t=0;5>t;t++)for(var e=0;5>e;e++)l[t+5*e]=e+(2*t+3*e)%5*5;for(var i=1,a=0;24>a;a++){for(var u=0,p=0,h=0;7>h;h++){if(1&i){var m=(1<m?p^=1<t;t++)p[t]=s.create()}();var h=u.SHA3=i.extend({cfg:i.cfg.extend({outputLength:512}),_doReset:function(){for(var t=this._state=[],e=0;25>e;e++)t[e]=new s.init;this.blockSize=(1600-2*this.cfg.outputLength)/32},_doProcessBlock:function(t,e){for(var n=this._state,r=this.blockSize/2,o=0;r>o;o++){var i=t[e+2*o],a=t[e+2*o+1];i=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8),a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8);var s=n[o];s.high^=a,s.low^=i}for(var u=0;24>u;u++){for(var h=0;5>h;h++){for(var m=0,d=0,g=0;5>g;g++){var s=n[h+5*g];m^=s.high,d^=s.low}var y=p[h];y.high=m,y.low=d}for(var h=0;5>h;h++)for(var v=p[(h+4)%5],b=p[(h+1)%5],w=b.high,_=b.low,m=v.high^(w<<1|_>>>31),d=v.low^(_<<1|w>>>31),g=0;5>g;g++){var s=n[h+5*g];s.high^=m,s.low^=d}for(var x=1;25>x;x++){var s=n[x],F=s.high,I=s.low,k=c[x];if(32>k)var m=F<>>32-k,d=I<>>32-k;else var m=I<>>64-k,d=F<>>64-k;var B=p[l[x]];B.high=m,B.low=d}var N=p[0],O=n[0];N.high=O.high,N.low=O.low;for(var h=0;5>h;h++)for(var g=0;5>g;g++){var x=h+5*g,s=n[x],T=p[x],A=p[(h+1)%5+5*g],P=p[(h+2)%5+5*g];s.high=T.high^~A.high&P.high,s.low=T.low^~A.low&P.low}var s=n[0],C=f[u];s.high^=C.high,s.low^=C.low}},_doFinalize:function(){var t=this._data,n=t.words,r=(8*this._nDataBytes,8*t.sigBytes),i=32*this.blockSize;n[r>>>5]|=1<<24-r%32,n[(e.ceil((r+1)/i)*i>>>5)-1]|=128,t.sigBytes=4*n.length,this._process();for(var a=this._state,s=this.cfg.outputLength/8,u=s/8,c=[],l=0;u>l;l++){var f=a[l],p=f.high,h=f.low;p=16711935&(p<<8|p>>>24)|4278255360&(p<<24|p>>>8),h=16711935&(h<<8|h>>>24)|4278255360&(h<<24|h>>>8),c.push(h),c.push(p)}return new o.init(c,s)},clone:function(){for(var t=i.clone.call(this),e=t._state=this._state.slice(0),n=0;25>n;n++)e[n]=e[n].clone();return t}});n.SHA3=i._createHelper(h),n.HmacSHA3=i._createHmacHelper(h)}(Math),t.SHA3})},{"./core":33,"./x64-core":35}],35:[function(t,e,n){!function(r,o){"object"==typeof n?e.exports=n=o(t("./core")):"function"==typeof define&&define.amd?define(["./core"],o):o(r.CryptoJS)}(this,function(t){return function(e){{var n=t,r=n.lib,o=r.Base,i=r.WordArray,a=n.x64={};a.Word=o.extend({init:function(t,e){this.high=t,this.low=e}}),a.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:8*t.length},toX32:function(){for(var t=this.words,e=t.length,n=[],r=0;e>r;r++){var o=t[r];n.push(o.high),n.push(o.low)}return i.create(n,this.sigBytes)},clone:function(){for(var t=o.clone.call(this),e=t.words=this.words.slice(0),n=e.length,r=0;n>r;r++)e[r]=e[r].clone();return t}})}}(),t})},{"./core":33}],"bignumber.js":[function(t,e,n){!function(n){"use strict";function r(t){function e(t,r){var o,i,a,s,u,c,l=this;if(!(l instanceof e))return W&&C(26,"constructor call without new",t),new e(t,r);if(null!=r&&z(r,2,64,R,"base")){if(r=0|r,c=t+"",10==r)return l=new e(t instanceof e?t:c),S(l,j+l.e+1,q);if((s="number"==typeof t)&&0*t!=0||!new RegExp("^-?"+(o="["+x.slice(0,r)+"]+")+"(?:\\."+o+")?$",37>r?"i":"").test(c))return d(l,c,s,r);s?(l.s=0>1/t?(c=c.slice(1),-1):1,W&&c.replace(/^0\.0*|\./,"").length>15&&C(R,_,t),s=!1):l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1,c=n(c,10,r,l.s)}else{if(t instanceof e)return l.s=t.s,l.e=t.e,l.c=(t=t.c)?t.slice():t,void(R=0);if((s="number"==typeof t)&&0*t==0){if(l.s=0>1/t?(t=-t,-1):1,t===~~t){for(i=0,a=t;a>=10;a/=10,i++);return l.e=i,l.c=[t],void(R=0)}c=t+""}else{if(!g.test(c=t+""))return d(l,c,s);l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1}}for((i=c.indexOf("."))>-1&&(c=c.replace(".","")),(a=c.search(/e/i))>0?(0>i&&(i=a),i+=+c.slice(a+1),c=c.substring(0,a)):0>i&&(i=c.length),a=0;48===c.charCodeAt(a);a++);for(u=c.length;48===c.charCodeAt(--u););if(c=c.slice(a,u+1))if(u=c.length,s&&W&&u>15&&C(R,_,l.s*t),i=i-a-1,i>G)l.c=l.e=null;else if(M>i)l.c=[l.e=0];else{if(l.e=i,l.c=[],a=(i+1)%I,0>i&&(a+=I),u>a){for(a&&l.c.push(+c.slice(0,a)),u-=I;u>a;)l.c.push(+c.slice(a,a+=I));c=c.slice(a),a=I-c.length}else a-=u;for(;a--;c+="0");l.c.push(+c)}else l.c=[l.e=0];R=0}function n(t,n,r,o){var a,s,u,l,p,h,m,d=t.indexOf("."),g=j,y=q;for(37>r&&(t=t.toLowerCase()),d>=0&&(u=$,$=0,t=t.replace(".",""),m=new e(r),p=m.pow(t.length-d),$=u,m.c=c(f(i(p.c),p.e),10,n),m.e=m.c.length),h=c(t,r,n),s=u=h.length;0==h[--u];h.pop());if(!h[0])return"0";if(0>d?--s:(p.c=h,p.e=s,p.s=o,p=D(p,m,g,y,n),h=p.c,l=p.r,s=p.e),a=s+g+1,d=h[a],u=n/2,l=l||0>a||null!=h[a+1],l=4>y?(null!=d||l)&&(0==y||y==(p.s<0?3:2)):d>u||d==u&&(4==y||l||6==y&&1&h[a-1]||y==(p.s<0?8:7)),1>a||!h[0])t=l?f("1",-g):"0";else{if(h.length=a,l)for(--n;++h[--a]>n;)h[a]=0,a||(++s,h.unshift(1));for(u=h.length;!h[--u];);for(d=0,t="";u>=d;t+=x.charAt(h[d++]));t=f(t,s)}return t}function h(t,n,r,o){var a,s,u,c,p;if(r=null!=r&&z(r,0,8,o,w)?0|r:q,!t.c)return t.toString();if(a=t.c[0],u=t.e,null==n)p=i(t.c),p=19==o||24==o&&L>=u?l(p,u):f(p,u);else if(t=S(new e(t),n,r),s=t.e,p=i(t.c),c=p.length,19==o||24==o&&(s>=n||L>=s)){for(;n>c;p+="0",c++);p=l(p,s)}else if(n-=u,p=f(p,s),s+1>c){if(--n>0)for(p+=".";n--;p+="0");}else if(n+=s-c,n>0)for(s+1==c&&(p+=".");n--;p+="0");return t.s<0&&a?"-"+p:p}function T(t,n){var r,o,i=0;for(u(t[0])&&(t=t[0]),r=new e(t[0]);++it||t>n||t!=p(t))&&C(r,(o||"decimal places")+(e>t||t>n?" out of range":" not an integer"),t),!0}function P(t,e,n){for(var r=1,o=e.length;!e[--o];e.pop());for(o=e[0];o>=10;o/=10,r++);return(n=r+n*I-1)>G?t.c=t.e=null:M>n?t.c=[t.e=0]:(t.e=n,t.c=e),t}function C(t,e,n){var r=new Error(["new BigNumber","cmp","config","div","divToInt","eq","gt","gte","lt","lte","minus","mod","plus","precision","random","round","shift","times","toDigits","toExponential","toFixed","toFormat","toFraction","pow","toPrecision","toString","BigNumber"][t]+"() "+e+": "+n);throw r.name="BigNumber Error",R=0,r}function S(t,e,n,r){var o,i,a,s,u,c,l,f=t.c,p=B;if(f){t:{for(o=1,s=f[0];s>=10;s/=10,o++);if(i=e-o,0>i)i+=I,a=e,u=f[c=0],l=u/p[o-a-1]%10|0;else if(c=y((i+1)/I),c>=f.length){if(!r)break t;for(;f.length<=c;f.push(0));u=l=0,o=1,i%=I,a=i-I+1}else{for(u=s=f[c],o=1;s>=10;s/=10,o++);i%=I,a=i-I+o,l=0>a?0:u/p[o-a-1]%10|0}if(r=r||0>e||null!=f[c+1]||(0>a?u:u%p[o-a-1]),r=4>n?(l||r)&&(0==n||n==(t.s<0?3:2)):l>5||5==l&&(4==n||r||6==n&&(i>0?a>0?u/p[o-a]:0:f[c-1])%10&1||n==(t.s<0?8:7)),1>e||!f[0])return f.length=0,r?(e-=t.e+1,f[0]=p[e%I],t.e=-e||0):f[0]=t.e=0,t;if(0==i?(f.length=c,s=1,c--):(f.length=c+1,s=p[I-i],f[c]=a>0?v(u/p[o-a]%p[a])*s:0),r)for(;;){if(0==c){for(i=1,a=f[0];a>=10;a/=10,i++);for(a=f[0]+=s,s=1;a>=10;a/=10,s++);i!=s&&(t.e++,f[0]==F&&(f[0]=1));break}if(f[c]+=s,f[c]!=F)break;f[c--]=0,s=1}for(i=f.length;0===f[--i];f.pop());}t.e>G?t.c=t.e=null:t.en?null!=(t=o[n++]):void 0};return a(e="DECIMAL_PLACES")&&z(t,0,O,2,e)&&(j=0|t),r[e]=j,a(e="ROUNDING_MODE")&&z(t,0,8,2,e)&&(q=0|t),r[e]=q,a(e="EXPONENTIAL_AT")&&(u(t)?z(t[0],-O,0,2,e)&&z(t[1],0,O,2,e)&&(L=0|t[0],U=0|t[1]):z(t,-O,O,2,e)&&(L=-(U=0|(0>t?-t:t)))),r[e]=[L,U],a(e="RANGE")&&(u(t)?z(t[0],-O,-1,2,e)&&z(t[1],1,O,2,e)&&(M=0|t[0],G=0|t[1]):z(t,-O,O,2,e)&&(0|t?M=-(G=0|(0>t?-t:t)):W&&C(2,e+" cannot be zero",t))),r[e]=[M,G],a(e="ERRORS")&&(t===!!t||1===t||0===t?(R=0,z=(W=!!t)?A:s):W&&C(2,e+b,t)),r[e]=W,a(e="CRYPTO")&&(t===!!t||1===t||0===t?(J=!(!t||!m||"object"!=typeof m),t&&!J&&W&&C(2,"crypto unavailable",m)):W&&C(2,e+b,t)),r[e]=J,a(e="MODULO_MODE")&&z(t,0,9,2,e)&&(V=0|t),r[e]=V,a(e="POW_PRECISION")&&z(t,0,O,2,e)&&($=0|t),r[e]=$,a(e="FORMAT")&&("object"==typeof t?X=t:W&&C(2,e+" not an object",t)),r[e]=X,r},e.max=function(){return T(arguments,E.lt)},e.min=function(){return T(arguments,E.gt)},e.random=function(){var t=9007199254740992,n=Math.random()*t&2097151?function(){return v(Math.random()*t)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)};return function(t){var r,o,i,a,s,u=0,c=[],l=new e(H);if(t=null!=t&&z(t,0,O,14)?0|t:j,a=y(t/I),J)if(m&&m.getRandomValues){for(r=m.getRandomValues(new Uint32Array(a*=2));a>u;)s=131072*r[u]+(r[u+1]>>>11),s>=9e15?(o=m.getRandomValues(new Uint32Array(2)),r[u]=o[0],r[u+1]=o[1]):(c.push(s%1e14),u+=2);u=a/2}else if(m&&m.randomBytes){for(r=m.randomBytes(a*=7);a>u;)s=281474976710656*(31&r[u])+1099511627776*r[u+1]+4294967296*r[u+2]+16777216*r[u+3]+(r[u+4]<<16)+(r[u+5]<<8)+r[u+6],s>=9e15?m.randomBytes(7).copy(r,u):(c.push(s%1e14),u+=7);u=a/7}else W&&C(14,"crypto unavailable",m);if(!u)for(;a>u;)s=n(),9e15>s&&(c[u++]=s%1e14);for(a=c[--u],t%=I,a&&t&&(s=B[I-t],c[u]=v(a/s)*s);0===c[u];c.pop(),u--);if(0>u)c=[i=0];else{for(i=-1;0===c[0];c.shift(),i-=I);for(u=1,s=c[0];s>=10;s/=10,u++);I>u&&(i-=I-u)}return l.e=i,l.c=c,l}}(),D=function(){function t(t,e,n){var r,o,i,a,s=0,u=t.length,c=e%N,l=e/N|0;for(t=t.slice();u--;)i=t[u]%N,a=t[u]/N|0,r=l*i+a*c,o=c*i+r%N*N+s,s=(o/n|0)+(r/N|0)+l*a,t[u]=o%n;return s&&t.unshift(s),t}function n(t,e,n,r){var o,i;if(n!=r)i=n>r?1:-1;else for(o=i=0;n>o;o++)if(t[o]!=e[o]){i=t[o]>e[o]?1:-1;break}return i}function r(t,e,n,r){for(var o=0;n--;)t[n]-=o,o=t[n]1;t.shift());}return function(i,a,s,u,c){var l,f,p,h,m,d,g,y,b,w,_,x,k,B,N,O,T,A=i.s==a.s?1:-1,P=i.c,C=a.c;if(!(P&&P[0]&&C&&C[0]))return new e(i.s&&a.s&&(P?!C||P[0]!=C[0]:C)?P&&0==P[0]||!C?0*A:A/0:0/0);for(y=new e(A),b=y.c=[],f=i.e-a.e,A=s+f+1,c||(c=F,f=o(i.e/I)-o(a.e/I),A=A/I|0),p=0;C[p]==(P[p]||0);p++);if(C[p]>(P[p]||0)&&f--,0>A)b.push(1),h=!0;else{for(B=P.length,O=C.length,p=0,A+=2,m=v(c/(C[0]+1)),m>1&&(C=t(C,m,c),P=t(P,m,c),O=C.length,B=P.length),k=O,w=P.slice(0,O),_=w.length;O>_;w[_++]=0);T=C.slice(),T.unshift(0),N=C[0],C[1]>=c/2&&N++;do{if(m=0,l=n(C,w,O,_),0>l){if(x=w[0],O!=_&&(x=x*c+(w[1]||0)),m=v(x/N),m>1)for(m>=c&&(m=c-1),d=t(C,m,c),g=d.length,_=w.length;1==n(d,w,g,_);)m--,r(d,g>O?T:C,g,c),g=d.length,l=1;else 0==m&&(l=m=1),d=C.slice(),g=d.length;if(_>g&&d.unshift(0),r(w,d,_,c),_=w.length,-1==l)for(;n(C,w,O,_)<1;)m++,r(w,_>O?T:C,_,c),_=w.length}else 0===l&&(m++,w=[0]);b[p++]=m,w[0]?w[_++]=P[k]||0:(w=[P[k]],_=1)}while((k++=10;A/=10,p++);S(y,s+(y.e=p+f*I-1)+1,u,h)}else y.e=f,y.r=+h;return y}}(),d=function(){var t=/^(-?)0([xbo])/i,n=/^([^.]+)\.$/,r=/^\.([^.]+)$/,o=/^-?(Infinity|NaN)$/,i=/^\s*\+|^\s+|\s+$/g;return function(a,s,u,c){var l,f=u?s:s.replace(i,"");if(o.test(f))a.s=isNaN(f)?null:0>f?-1:1;else{if(!u&&(f=f.replace(t,function(t,e,n){return l="x"==(n=n.toLowerCase())?16:"b"==n?2:8,c&&c!=l?t:e}),c&&(l=c,f=f.replace(n,"$1").replace(r,"0.$1")),s!=f))return new e(f,l);W&&C(R,"not a"+(c?" base "+c:"")+" number",s),a.s=null}a.c=a.e=null,R=0}}(),E.absoluteValue=E.abs=function(){var t=new e(this);return t.s<0&&(t.s=1),t},E.ceil=function(){return S(new e(this),this.e+1,2)},E.comparedTo=E.cmp=function(t,n){return R=1,a(this,new e(t,n))},E.decimalPlaces=E.dp=function(){var t,e,n=this.c;if(!n)return null;if(t=((e=n.length-1)-o(this.e/I))*I,e=n[e])for(;e%10==0;e/=10,t--);return 0>t&&(t=0),t},E.dividedBy=E.div=function(t,n){return R=3,D(this,new e(t,n),j,q)},E.dividedToIntegerBy=E.divToInt=function(t,n){return R=4,D(this,new e(t,n),0,1)},E.equals=E.eq=function(t,n){return R=5,0===a(this,new e(t,n))},E.floor=function(){return S(new e(this),this.e+1,3)},E.greaterThan=E.gt=function(t,n){return R=6,a(this,new e(t,n))>0},E.greaterThanOrEqualTo=E.gte=function(t,n){return R=7,1===(n=a(this,new e(t,n)))||0===n},E.isFinite=function(){return!!this.c},E.isInteger=E.isInt=function(){return!!this.c&&o(this.e/I)>this.c.length-2},E.isNaN=function(){return!this.s},E.isNegative=E.isNeg=function(){return this.s<0},E.isZero=function(){return!!this.c&&0==this.c[0]},E.lessThan=E.lt=function(t,n){return R=8,a(this,new e(t,n))<0},E.lessThanOrEqualTo=E.lte=function(t,n){return R=9,-1===(n=a(this,new e(t,n)))||0===n},E.minus=E.sub=function(t,n){var r,i,a,s,u=this,c=u.s;if(R=10,t=new e(t,n),n=t.s,!c||!n)return new e(0/0);if(c!=n)return t.s=-n,u.plus(t);var l=u.e/I,f=t.e/I,p=u.c,h=t.c;if(!l||!f){if(!p||!h)return p?(t.s=-n,t):new e(h?u:0/0);if(!p[0]||!h[0])return h[0]?(t.s=-n,t):new e(p[0]?u:3==q?-0:0)}if(l=o(l),f=o(f),p=p.slice(),c=l-f){for((s=0>c)?(c=-c,a=p):(f=l,a=h),a.reverse(),n=c;n--;a.push(0));a.reverse()}else for(i=(s=(c=p.length)<(n=h.length))?c:n,c=n=0;i>n;n++)if(p[n]!=h[n]){s=p[n]0)for(;n--;p[r++]=0);for(n=F-1;i>c;){if(p[--i]0?(u=s,r=l):(a=-a,r=c),r.reverse();a--;r.push(0));r.reverse()}for(a=c.length,n=l.length,0>a-n&&(r=l,l=c,c=r,n=a),a=0;n;)a=(c[--n]=c[n]+l[n]+a)/F|0,c[n]%=F;return a&&(c.unshift(a),++u),P(t,c,u)},E.precision=E.sd=function(t){var e,n,r=this,o=r.c;if(null!=t&&t!==!!t&&1!==t&&0!==t&&(W&&C(13,"argument"+b,t),t!=!!t&&(t=null)),!o)return null;if(n=o.length-1,e=n*I+1,n=o[n]){for(;n%10==0;n/=10,e--);for(n=o[0];n>=10;n/=10, +e++);}return t&&r.e+1>e&&(e=r.e+1),e},E.round=function(t,n){var r=new e(this);return(null==t||z(t,0,O,15))&&S(r,~~t+this.e+1,null!=n&&z(n,0,8,15,w)?0|n:q),r},E.shift=function(t){var n=this;return z(t,-k,k,16,"argument")?n.times("1e"+p(t)):new e(n.c&&n.c[0]&&(-k>t||t>k)?n.s*(0>t?0:1/0):n)},E.squareRoot=E.sqrt=function(){var t,n,r,a,s,u=this,c=u.c,l=u.s,f=u.e,p=j+4,h=new e("0.5");if(1!==l||!c||!c[0])return new e(!l||0>l&&(!c||c[0])?0/0:c?u:1/0);if(l=Math.sqrt(+u),0==l||l==1/0?(n=i(c),(n.length+f)%2==0&&(n+="0"),l=Math.sqrt(n),f=o((f+1)/2)-(0>f||f%2),l==1/0?n="1e"+f:(n=l.toExponential(),n=n.slice(0,n.indexOf("e")+1)+f),r=new e(n)):r=new e(l+""),r.c[0])for(f=r.e,l=f+p,3>l&&(l=0);;)if(s=r,r=h.times(s.plus(D(u,s,p,1))),i(s.c).slice(0,l)===(n=i(r.c)).slice(0,l)){if(r.el&&(g=w,w=_,_=g,a=l,l=h,h=a),a=l+h,g=[];a--;g.push(0));for(y=F,v=N,a=h;--a>=0;){for(r=0,m=_[a]%v,d=_[a]/v|0,u=l,s=a+u;s>a;)f=w[--u]%v,p=w[u]/v|0,c=d*f+p*m,f=m*f+c%v*v+g[s]+r,r=(f/y|0)+(c/v|0)+d*p,g[s--]=f%y;g[s]=r}return r?++i:g.shift(),P(t,g,i)},E.toDigits=function(t,n){var r=new e(this);return t=null!=t&&z(t,1,O,18,"precision")?0|t:null,n=null!=n&&z(n,0,8,18,w)?0|n:q,t?S(r,t,n):r},E.toExponential=function(t,e){return h(this,null!=t&&z(t,0,O,19)?~~t+1:null,e,19)},E.toFixed=function(t,e){return h(this,null!=t&&z(t,0,O,20)?~~t+this.e+1:null,e,20)},E.toFormat=function(t,e){var n=h(this,null!=t&&z(t,0,O,21)?~~t+this.e+1:null,e,21);if(this.c){var r,o=n.split("."),i=+X.groupSize,a=+X.secondaryGroupSize,s=X.groupSeparator,u=o[0],c=o[1],l=this.s<0,f=l?u.slice(1):u,p=f.length;if(a&&(r=i,i=a,a=r,p-=r),i>0&&p>0){for(r=p%i||i,u=f.substr(0,r);p>r;r+=i)u+=s+f.substr(r,i);a>0&&(u+=s+f.slice(r)),l&&(u="-"+u)}n=c?u+X.decimalSeparator+((a=+X.fractionGroupSize)?c.replace(new RegExp("\\d{"+a+"}\\B","g"),"$&"+X.fractionGroupSeparator):c):u}return n},E.toFraction=function(t){var n,r,o,a,s,u,c,l,f,p=W,h=this,m=h.c,d=new e(H),g=r=new e(H),y=c=new e(H);if(null!=t&&(W=!1,u=new e(t),W=p,(!(p=u.isInt())||u.lt(H))&&(W&&C(22,"max denominator "+(p?"out of range":"not an integer"),t),t=!p&&u.c&&S(u,u.e+1,1).gte(H)?u:null)),!m)return h.toString();for(f=i(m),a=d.e=f.length-h.e-1,d.c[0]=B[(s=a%I)<0?I+s:s],t=!t||u.cmp(d)>0?a>0?d:g:u,s=G,G=1/0,u=new e(f),c.c[0]=0;l=D(u,d,0,1),o=r.plus(l.times(y)),1!=o.cmp(t);)r=y,y=o,g=c.plus(l.times(o=g)),c=o,d=u.minus(l.times(o=d)),u=o;return o=D(t.minus(r),y,0,1),c=c.plus(o.times(g)),r=r.plus(o.times(y)),c.s=g.s=h.s,a*=2,n=D(g,y,a,q).minus(h).abs().cmp(D(c,r,a,q).minus(h).abs())<1?[g.toString(),y.toString()]:[c.toString(),r.toString()],G=s,n},E.toNumber=function(){var t=this;return+t||(t.s?0*t.s:0/0)},E.toPower=E.pow=function(t){var n,r,o=v(0>t?-t:+t),i=this;if(!z(t,-k,k,23,"exponent")&&(!isFinite(t)||o>k&&(t/=0)||parseFloat(t)!=t&&!(t=0/0)))return new e(Math.pow(+i,t));for(n=$?y($/I+2):0,r=new e(H);;){if(o%2){if(r=r.times(i),!r.c)break;n&&r.c.length>n&&(r.c.length=n)}if(o=v(o/2),!o)break;i=i.times(i),n&&i.c&&i.c.length>n&&(i.c.length=n)}return 0>t&&(r=H.div(r)),n?S(r,$,q):r},E.toPrecision=function(t,e){return h(this,null!=t&&z(t,1,O,24,"precision")?0|t:null,e,24)},E.toString=function(t){var e,r=this,o=r.s,a=r.e;return null===a?o?(e="Infinity",0>o&&(e="-"+e)):e="NaN":(e=i(r.c),e=null!=t&&z(t,2,64,25,"base")?n(f(e,a),0|t,10,o):L>=a||a>=U?l(e,a):f(e,a),0>o&&r.c[0]&&(e="-"+e)),e},E.truncated=E.trunc=function(){return S(new e(this),this.e+1,1)},E.valueOf=E.toJSON=function(){return this.toString()},null!=t&&e.config(t),e}function o(t){var e=0|t;return t>0||t===e?e:e-1}function i(t){for(var e,n,r=1,o=t.length,i=t[0]+"";o>r;){for(e=t[r++]+"",n=I-e.length;n--;e="0"+e);i+=e}for(o=i.length;48===i.charCodeAt(--o););return i.slice(0,o+1||1)}function a(t,e){var n,r,o=t.c,i=e.c,a=t.s,s=e.s,u=t.e,c=e.e;if(!a||!s)return null;if(n=o&&!o[0],r=i&&!i[0],n||r)return n?r?0:-s:a;if(a!=s)return a;if(n=0>a,r=u==c,!o||!i)return r?0:!o^n?1:-1;if(!r)return u>c^n?1:-1;for(s=(u=o.length)<(c=i.length)?u:c,a=0;s>a;a++)if(o[a]!=i[a])return o[a]>i[a]^n?1:-1;return u==c?0:u>c^n?1:-1}function s(t,e,n){return(t=p(t))>=e&&n>=t}function u(t){return"[object Array]"==Object.prototype.toString.call(t)}function c(t,e,n){for(var r,o,i=[0],a=0,s=t.length;s>a;){for(o=i.length;o--;i[o]*=e);for(i[r=0]+=x.indexOf(t.charAt(a++));rn-1&&(null==i[r+1]&&(i[r+1]=0),i[r+1]+=i[r]/n|0,i[r]%=n)}return i.reverse()}function l(t,e){return(t.length>1?t.charAt(0)+"."+t.slice(1):t)+(0>e?"e":"e+")+e}function f(t,e){var n,r;if(0>e){for(r="0.";++e;r+="0");t=r+t}else if(n=t.length,++e>n){for(r="0",e-=n;--e;r+="0");t+=r}else n>e&&(t=t.slice(0,e)+"."+t.slice(e));return t}function p(t){return t=parseFloat(t),0>t?y(t):v(t)}var h,m,d,g=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,y=Math.ceil,v=Math.floor,b=" not a boolean or binary digit",w="rounding mode",_="number type has more than 15 significant digits",x="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",F=1e14,I=14,k=9007199254740991,B=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],N=1e7,O=1e9;if(h=r(),"function"==typeof define&&define.amd)define(function(){return h});else if("undefined"!=typeof e&&e.exports){if(e.exports=h,!m)try{m=t("crypto")}catch(T){}}else n.BigNumber=h}(this)},{crypto:32}],web3:[function(t,e,n){var r=t("./lib/web3");r.providers.HttpProvider=t("./lib/web3/httpprovider"),r.providers.IpcProvider=t("./lib/web3/ipcprovider"),r.eth.contract=t("./lib/web3/contract"),r.eth.namereg=t("./lib/web3/namereg"),r.eth.sendIBANTransaction=t("./lib/web3/transfer"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/ipcprovider":22,"./lib/web3/namereg":25,"./lib/web3/transfer":30}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/example/balance.html b/libjsqrc/ethereumjs/example/balance.html index 02240be8b..d4297f5dd 100644 --- a/libjsqrc/ethereumjs/example/balance.html +++ b/libjsqrc/ethereumjs/example/balance.html @@ -16,7 +16,7 @@ document.getElementById('coinbase').innerText = 'coinbase: ' + coinbase; document.getElementById('original').innerText = ' original balance: ' + originalBalance + ' watching...'; - web3.eth.filter('pending').watch(function() { + web3.eth.filter('latest').watch(function() { var currentBalance = web3.eth.getBalance(coinbase).toNumber(); document.getElementById("current").innerText = 'current: ' + currentBalance; document.getElementById("diff").innerText = 'diff: ' + (currentBalance - originalBalance); diff --git a/libjsqrc/ethereumjs/example/contract.html b/libjsqrc/ethereumjs/example/contract.html index af7546fc7..097b66c70 100644 --- a/libjsqrc/ethereumjs/example/contract.html +++ b/libjsqrc/ethereumjs/example/contract.html @@ -31,25 +31,22 @@ // let's assume that coinbase is our account web3.eth.defaultAccount = web3.eth.coinbase; - var watch = web3.eth.filter('latest'); - // create contract - myContract = web3.eth.contract(abi).new({data: code}); - console.log('address: ' + myContract.address); document.getElementById('status').innerText = "transaction sent, waiting for confirmation"; - watch.watch(function (err, hash) { - var block = web3.eth.getBlock(hash, true); - var contractMined = block.transactions.reduce(function (mined, th) { - // TODO: compiled code do not have 0x prefix - return mined || (th.from === web3.eth.defaultAccount && th.input.indexOf(code) !== -1); - }, false); + web3.eth.contract(abi).new({data: code}, function (err, contract) { + if(err) { + console.error(err); + return; + + // callback fires twice, we only want the second call when the contract is deployed + } else if(contract.address){ - if (contractMined) { + myContract = contract; + console.log('address: ' + myContract.address); document.getElementById('status').innerText = 'Mined!'; document.getElementById('call').style.visibility = 'visible'; } }); - } function callExampleContract() { diff --git a/libjsqrc/ethereumjs/example/contract_array.html b/libjsqrc/ethereumjs/example/contract_array.html index 421e42baf..752eb9ac4 100644 --- a/libjsqrc/ethereumjs/example/contract_array.html +++ b/libjsqrc/ethereumjs/example/contract_array.html @@ -31,25 +31,23 @@ // let's assume that coinbase is our account web3.eth.defaultAccount = web3.eth.coinbase; - var watch = web3.eth.filter('latest'); - // create contract - myContract = web3.eth.contract(abi).new({data: code}); - console.log('address: ' + myContract.address); document.getElementById('status').innerText = "transaction sent, waiting for confirmation"; - watch.watch(function (err, hash) { - var block = web3.eth.getBlock(hash, true); - var contractMined = block.transactions.reduce(function (mined, th) { - // TODO: compiled code do not have 0x prefix - return mined || (th.from === web3.eth.defaultAccount && th.input.indexOf(code) !== -1); - }, false); + web3.eth.contract(abi).new({data: code}, function (err, contract) { + if (err) { + console.error(err); + return; + + // callback fires twice, we only want the second call when the contract is deployed + } else if(contract.address){ + + myContract = contract; + console.log('address: ' + myContract.address); - if (contractMined) { document.getElementById('status').innerText = 'Mined!'; document.getElementById('call').style.visibility = 'visible'; } }); - } function callExampleContract() { diff --git a/libjsqrc/ethereumjs/example/event_inc.html b/libjsqrc/ethereumjs/example/event_inc.html index e4a1211b4..bb3c99fc4 100644 --- a/libjsqrc/ethereumjs/example/event_inc.html +++ b/libjsqrc/ethereumjs/example/event_inc.html @@ -35,29 +35,25 @@ // let's assume that we have a private key to coinbase ;) web3.eth.defaultAccount = web3.eth.coinbase; - var watch = web3.eth.filter('latest'); - - contract = web3.eth.contract(abi).new({data: code}); - - console.log('address: ' + contract.address); - document.getElementById('create').style.visibility = 'hidden'; document.getElementById('status').innerText = "transaction sent, waiting for confirmation"; - watch.watch(function (err, hash) { - var block = web3.eth.getBlock(hash, true); - var contractMined = block.transactions.reduce(function (mined, th) { - // TODO: compiled code do not have 0x prefix - return mined || (th.from === web3.eth.defaultAccount && th.input.indexOf(code) !== -1); - }, false); - if (contractMined) { + web3.eth.contract(abi).new({data: code}, function (err, c) { + if (err) { + console.error(err); + return; + + // callback fires twice, we only want the second call when the contract is deployed + } else if(contract.address){ + + contract = c; + console.log('address: ' + contract.address); document.getElementById('status').innerText = 'Mined!'; document.getElementById('call').style.visibility = 'visible'; + + inc = contract.Incremented({odd: true}, update); } }); - - inc = contract.Incremented({odd: true}); - inc.watch(update); }; var counter = 0; diff --git a/libjsqrc/ethereumjs/index.js b/libjsqrc/ethereumjs/index.js index ef2752dab..e808844f0 100644 --- a/libjsqrc/ethereumjs/index.js +++ b/libjsqrc/ethereumjs/index.js @@ -1,6 +1,8 @@ var web3 = require('./lib/web3'); + web3.providers.HttpProvider = require('./lib/web3/httpprovider'); -web3.providers.QtSyncProvider = require('./lib/web3/qtsync'); +web3.providers.IpcProvider = require('./lib/web3/ipcprovider'); + web3.eth.contract = require('./lib/web3/contract'); web3.eth.namereg = require('./lib/web3/namereg'); web3.eth.sendIBANTransaction = require('./lib/web3/transfer'); diff --git a/libjsqrc/ethereumjs/lib/version.json b/libjsqrc/ethereumjs/lib/version.json index 4fe134016..2069fe234 100644 --- a/libjsqrc/ethereumjs/lib/version.json +++ b/libjsqrc/ethereumjs/lib/version.json @@ -1,3 +1,3 @@ { - "version": "0.7.1" + "version": "0.9.0" } diff --git a/libjsqrc/ethereumjs/lib/web3.js b/libjsqrc/ethereumjs/lib/web3.js index 8f684d132..6f5a48e02 100644 --- a/libjsqrc/ethereumjs/lib/web3.js +++ b/libjsqrc/ethereumjs/lib/web3.js @@ -101,6 +101,9 @@ web3.setProvider = function (provider) { this.currentProvider = provider; RequestManager.getInstance().setProvider(provider); }; +web3.isConnected = function(){ + return (this.currentProvider && this.currentProvider.isConnected()); +}; web3.reset = function () { RequestManager.getInstance().reset(); c.defaultBlock = 'latest'; diff --git a/libjsqrc/ethereumjs/lib/web3/allevents.js b/libjsqrc/ethereumjs/lib/web3/allevents.js index 190643034..37e9cf04c 100644 --- a/libjsqrc/ethereumjs/lib/web3/allevents.js +++ b/libjsqrc/ethereumjs/lib/web3/allevents.js @@ -42,7 +42,6 @@ AllSolidityEvents.prototype.encode = function (options) { result[f] = formatters.inputBlockNumberFormatter(options[f]); }); - result.topics = [null, null, null, null, null]; // match all topics result.address = this._address; return result; diff --git a/libjsqrc/ethereumjs/lib/web3/batch.js b/libjsqrc/ethereumjs/lib/web3/batch.js index ca32bf725..6b6b6f512 100644 --- a/libjsqrc/ethereumjs/lib/web3/batch.js +++ b/libjsqrc/ethereumjs/lib/web3/batch.js @@ -21,6 +21,8 @@ */ var RequestManager = require('./requestmanager'); +var Jsonrpc = require('./jsonrpc'); +var errors = require('./errors'); var Batch = function () { this.requests = []; @@ -47,11 +49,14 @@ Batch.prototype.execute = function () { results = results || []; requests.map(function (request, index) { return results[index] || {}; - }).map(function (result, index) { - return requests[index].format ? requests[index].format(result.result) : result.result; }).forEach(function (result, index) { if (requests[index].callback) { - requests[index].callback(err, result); + + if (!Jsonrpc.getInstance().isValidResponse(result)) { + return requests[index].callback(errors.InvalidResponse(result)); + } + + requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result)); } }); }); diff --git a/libjsqrc/ethereumjs/lib/web3/contract.js b/libjsqrc/ethereumjs/lib/web3/contract.js index 433e7ecba..01c16de66 100644 --- a/libjsqrc/ethereumjs/lib/web3/contract.js +++ b/libjsqrc/ethereumjs/lib/web3/contract.js @@ -96,6 +96,79 @@ var contract = function (abi) { return new ContractFactory(abi); }; +/** + * Should be called to check if the contract gets properly deployed on the blockchain. + * + * @method checkForContractAddress + * @param {Object} contract + * @param {Function} callback + * @returns {Undefined} + */ +var checkForContractAddress = function(contract, abi, callback){ + var count = 0, + callbackFired = false; + + // wait for receipt + var filter = web3.eth.filter('latest', function(e){ + if(!e && !callbackFired) { + count++; + + // console.log('Checking for contract address', count); + + // stop watching after 50 blocks (timeout) + if(count > 50) { + + filter.stopWatching(); + callbackFired = true; + + if(callback) + callback(new Error('Contract transaction couldn\'t be found after 50 blocks')); + else + throw new Error('Contract transaction couldn\'t be found after 50 blocks'); + + + } else { + + web3.eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){ + if(receipt && !callbackFired) { + + web3.eth.getCode(receipt.contractAddress, function(e, code){ + /*jshint maxcomplexity: 5 */ + + if(callbackFired) + return; + + filter.stopWatching(); + callbackFired = true; + + if(code.length > 2) { + + // console.log('Contract code deployed!'); + + contract.address = receipt.contractAddress; + + // attach events and methods + addFunctionsToContract(contract, abi); + addEventsToContract(contract, abi); + + // call callback for the second time + if(callback) + callback(null, contract); + + } else { + if(callback) + callback(new Error('The contract code couldn\'t be stored, please check your gas amount.')); + else + throw new Error('The contract code couldn\'t be stored, please check your gas amount.'); + } + }); + } + }); + } + } + }); +}; + /** * Should be called to create new ContractFactory instance * @@ -114,10 +187,12 @@ var ContractFactory = function (abi) { * @param {Any} contract constructor param2 (optional) * @param {Object} contract transaction object (required) * @param {Function} callback - * @returns {Contract} returns contract if no callback was passed, - * otherwise calls callback function (err, contract) + * @returns {Contract} returns contract instance */ ContractFactory.prototype.new = function () { + var _this = this; + var contract = new Contract(this.abi); + // parse arguments var options = {}; // required! var callback; @@ -137,18 +212,31 @@ ContractFactory.prototype.new = function () { var bytes = encodeConstructorParams(this.abi, args); options.data += bytes; - if (!callback) { - var address = web3.eth.sendTransaction(options); - return this.at(address); + + if(callback) { + + // wait for the contract address adn check if the code was deployed + web3.eth.sendTransaction(options, function (err, hash) { + if (err) { + callback(err); + } else { + // add the transaction hash + contract.transactionHash = hash; + + // call callback for the first time + callback(null, contract); + + checkForContractAddress(contract, _this.abi, callback); + } + }); + } else { + var hash = web3.eth.sendTransaction(options); + // add the transaction hash + contract.transactionHash = hash; + checkForContractAddress(contract, _this.abi); } - - var self = this; - web3.eth.sendTransaction(options, function (err, address) { - if (err) { - callback(err); - } - self.at(address, callback); - }); + + return contract; }; /** @@ -161,12 +249,17 @@ ContractFactory.prototype.new = function () { * otherwise calls callback function (err, contract) */ ContractFactory.prototype.at = function (address, callback) { + var contract = new Contract(this.abi, address); // TODO: address is required + + // attach functions + addFunctionsToContract(contract, this.abi); + addEventsToContract(contract, this.abi); if (callback) { - callback(null, new Contract(this.abi, address)); + callback(null, contract); } - return new Contract(this.abi, address); + return contract; }; /** @@ -178,8 +271,6 @@ ContractFactory.prototype.at = function (address, callback) { */ var Contract = function (abi, address) { this.address = address; - addFunctionsToContract(this, abi); - addEventsToContract(this, abi); }; module.exports = contract; diff --git a/libjsqrc/ethereumjs/lib/web3/errors.js b/libjsqrc/ethereumjs/lib/web3/errors.js index 5b6107fd5..58d5f9d04 100644 --- a/libjsqrc/ethereumjs/lib/web3/errors.js +++ b/libjsqrc/ethereumjs/lib/web3/errors.js @@ -31,7 +31,7 @@ module.exports = { return new Error('Providor not set or invalid'); }, InvalidResponse: function (result){ - var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response'; + var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: '+ result; return new Error(message); } }; diff --git a/libjsqrc/ethereumjs/lib/web3/eth.js b/libjsqrc/ethereumjs/lib/web3/eth.js index 87a2b290c..3e119e84d 100644 --- a/libjsqrc/ethereumjs/lib/web3/eth.js +++ b/libjsqrc/ethereumjs/lib/web3/eth.js @@ -152,6 +152,13 @@ var getTransactionFromBlock = new Method({ outputFormatter: formatters.outputTransactionFormatter }); +var getTransactionReceipt = new Method({ + name: 'getTransactionReceipt', + call: 'eth_getTransactionReceipt', + params: 1, + outputFormatter: formatters.outputTransactionReceiptFormatter +}); + var getTransactionCount = new Method({ name: 'getTransactionCount', call: 'eth_getTransactionCount', @@ -160,6 +167,13 @@ var getTransactionCount = new Method({ outputFormatter: utils.toDecimal }); +var sendRawTransaction = new Method({ + name: 'sendRawTransaction', + call: 'eth_sendRawTransaction', + params: 1, + inputFormatter: [null] +}); + var sendTransaction = new Method({ name: 'sendTransaction', call: 'eth_sendTransaction', @@ -223,9 +237,11 @@ var methods = [ getBlockUncleCount, getTransaction, getTransactionFromBlock, + getTransactionReceipt, getTransactionCount, call, estimateGas, + sendRawTransaction, sendTransaction, compileSolidity, compileLLL, diff --git a/libjsqrc/ethereumjs/lib/web3/event.js b/libjsqrc/ethereumjs/lib/web3/event.js index f2b40e3ea..101fa09ca 100644 --- a/libjsqrc/ethereumjs/lib/web3/event.js +++ b/libjsqrc/ethereumjs/lib/web3/event.js @@ -103,8 +103,8 @@ SolidityEvent.prototype.encode = function (indexed, options) { result.topics = []; + result.address = this._address; if (!this._anonymous) { - result.address = this._address; result.topics.push('0x' + this.signature()); } diff --git a/libjsqrc/ethereumjs/lib/web3/filter.js b/libjsqrc/ethereumjs/lib/web3/filter.js index 0361aa0b8..e340d7bad 100644 --- a/libjsqrc/ethereumjs/lib/web3/filter.js +++ b/libjsqrc/ethereumjs/lib/web3/filter.js @@ -90,9 +90,11 @@ var getLogsAtStart = function(self, callback){ callback(err); } - messages.forEach(function (message) { - callback(null, message); - }); + if(utils.isArray(messages)) { + messages.forEach(function (message) { + callback(null, message); + }); + } }); } }; diff --git a/libjsqrc/ethereumjs/lib/web3/formatters.js b/libjsqrc/ethereumjs/lib/web3/formatters.js index 743527e49..1f88d5b0f 100644 --- a/libjsqrc/ethereumjs/lib/web3/formatters.js +++ b/libjsqrc/ethereumjs/lib/web3/formatters.js @@ -85,8 +85,8 @@ var inputTransactionFormatter = function (options){ * Formats the output of a transaction to its proper values * * @method outputTransactionFormatter - * @param {Object} transaction - * @returns {Object} transaction + * @param {Object} tx + * @returns {Object} */ var outputTransactionFormatter = function (tx){ if(tx.blockNumber !== null) @@ -100,12 +100,36 @@ var outputTransactionFormatter = function (tx){ return tx; }; +/** + * Formats the output of a transaction receipt to its proper values + * + * @method outputTransactionReceiptFormatter + * @param {Object} receipt + * @returns {Object} +*/ +var outputTransactionReceiptFormatter = function (receipt){ + if(receipt.blockNumber !== null) + receipt.blockNumber = utils.toDecimal(receipt.blockNumber); + if(receipt.transactionIndex !== null) + receipt.transactionIndex = utils.toDecimal(receipt.transactionIndex); + receipt.cumulativeGasUsed = utils.toDecimal(receipt.cumulativeGasUsed); + receipt.gasUsed = utils.toDecimal(receipt.gasUsed); + + if(utils.isArray(receipt.logs)) { + receipt.logs = receipt.logs.map(function(log){ + return outputLogFormatter(log); + }); + } + + return receipt; +}; + /** * Formats the output of a block to its proper values * * @method outputBlockFormatter - * @param {Object} block object - * @returns {Object} block object + * @param {Object} block + * @returns {Object} */ var outputBlockFormatter = function(block) { @@ -213,6 +237,7 @@ module.exports = { inputPostFormatter: inputPostFormatter, outputBigNumberFormatter: outputBigNumberFormatter, outputTransactionFormatter: outputTransactionFormatter, + outputTransactionReceiptFormatter: outputTransactionReceiptFormatter, outputBlockFormatter: outputBlockFormatter, outputLogFormatter: outputLogFormatter, outputPostFormatter: outputPostFormatter diff --git a/libjsqrc/ethereumjs/lib/web3/httpprovider.js b/libjsqrc/ethereumjs/lib/web3/httpprovider.js index 6bdf32a85..2a8fabd0c 100644 --- a/libjsqrc/ethereumjs/lib/web3/httpprovider.js +++ b/libjsqrc/ethereumjs/lib/web3/httpprovider.js @@ -19,12 +19,11 @@ * Marek Kotewicz * Marian Oancea * Fabian Vogelsteller - * @date 2014 + * @date 2015 */ "use strict"; -// resolves the problem for electron/atom shell environments, which use node integration, but have no process variable available var XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line var errors = require('./errors'); @@ -32,6 +31,25 @@ var HttpProvider = function (host) { this.host = host || 'http://localhost:8545'; }; +HttpProvider.prototype.isConnected = function() { + var request = new XMLHttpRequest(); + + request.open('POST', this.host, false); + request.setRequestHeader('Content-type','application/json'); + + try { + request.send(JSON.stringify({ + id: 9999999999, + jsonrpc: '2.0', + method: 'net_listening', + params: [] + })); + return true; + } catch(e) { + return false; + } +}; + HttpProvider.prototype.send = function (payload) { var request = new XMLHttpRequest(); @@ -56,7 +74,7 @@ HttpProvider.prototype.send = function (payload) { try { result = JSON.parse(result); } catch(e) { - throw errors.InvalidResponse(result); + throw errors.InvalidResponse(request.responseText); } return result; @@ -72,7 +90,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { try { result = JSON.parse(result); } catch(e) { - error = errors.InvalidResponse(result); + error = errors.InvalidResponse(request.responseText); } callback(error, result); diff --git a/libjsqrc/ethereumjs/lib/web3/ipcprovider.js b/libjsqrc/ethereumjs/lib/web3/ipcprovider.js new file mode 100644 index 000000000..8bc8827af --- /dev/null +++ b/libjsqrc/ethereumjs/lib/web3/ipcprovider.js @@ -0,0 +1,211 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file ipcprovider.js + * @authors: + * Fabian Vogelsteller + * @date 2015 + */ + +"use strict"; + +var utils = require('../utils/utils'); +var errors = require('./errors'); + +var errorTimeout = '{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}'; + + +var IpcProvider = function (path, net) { + var _this = this; + this.responseCallbacks = {}; + this.path = path; + + net = net || require('net'); + + this.connection = net.connect({path: this.path}); + + this.connection.on('error', function(e){ + console.error('IPC Connection Error', e); + _this._timeout(); + }); + + this.connection.on('end', function(){ + _this._timeout(); + }); + + + // LISTEN FOR CONNECTION RESPONSES + this.connection.on('data', function(data) { + /*jshint maxcomplexity: 6 */ + + _this._parseResponse(data.toString()).forEach(function(result){ + + var id = null; + + // get the id which matches the returned id + if(utils.isArray(result)) { + result.forEach(function(load){ + if(_this.responseCallbacks[load.id]) + id = load.id; + }); + } else { + id = result.id; + } + + // fire the callback + if(_this.responseCallbacks[id]) { + _this.responseCallbacks[id](null, result); + delete _this.responseCallbacks[id]; + } + }); + }); +}; + +/** +Will parse the response and make an array out of it. + +@method _parseResponse +@param {String} data +*/ +IpcProvider.prototype._parseResponse = function(data) { + var _this = this, + returnValues = []; + + // DE-CHUNKER + var dechunkedData = data + .replace(/\}\{/g,'}|--|{') // }{ + .replace(/\}\]\[\{/g,'}]|--|[{') // }][{ + .replace(/\}\[\{/g,'}|--|[{') // }[{ + .replace(/\}\]\{/g,'}]|--|{') // }]{ + .split('|--|'); + + dechunkedData.forEach(function(data){ + + // prepend the last chunk + if(_this.lastChunk) + data = _this.lastChunk + data; + + var result = null; + + try { + result = JSON.parse(data); + + } catch(e) { + + _this.lastChunk = data; + + // start timeout to cancel all requests + clearTimeout(_this.lastChunkTimeout); + _this.lastChunkTimeout = setTimeout(function(){ + _this.timeout(); + throw errors.InvalidResponse(data); + }, 1000 * 15); + + return; + } + + // cancel timeout and set chunk to null + clearTimeout(_this.lastChunkTimeout); + _this.lastChunk = null; + + if(result) + returnValues.push(result); + }); + + return returnValues; +}; + + +/** +Get the adds a callback to the responseCallbacks object, +which will be called if a response matching the response Id will arrive. + +@method _addResponseCallback +*/ +IpcProvider.prototype._addResponseCallback = function(payload, callback) { + var id = payload.id || payload[0].id; + var method = payload.method || payload[0].method; + + this.responseCallbacks[id] = callback; + this.responseCallbacks[id].method = method; +}; + +/** +Timeout all requests when the end/error event is fired + +@method _timeout +*/ +IpcProvider.prototype._timeout = function() { + for(var key in this.responseCallbacks) { + if(this.responseCallbacks.hasOwnProperty(key)){ + this.responseCallbacks[key](errorTimeout.replace('__id__', key).replace('__method__', this.responseCallbacks[key].method)); + delete this.responseCallbacks[key]; + } + } +}; + + +/** +Check if the current connection is still valid. + +@method isConnected +*/ +IpcProvider.prototype.isConnected = function() { + var _this = this; + + // try reconnect, when connection is gone + if(!_this.connection.writable) + _this.connection.connect({path: _this.path}); + + return !!this.connection.writable; +}; + +IpcProvider.prototype.send = function (payload) { + + if(this.connection.writeSync) { + var result; + + // try reconnect, when connection is gone + if(!this.connection.writable) + this.connection.connect({path: this.path}); + + var data = this.connection.writeSync(JSON.stringify(payload)); + + try { + result = JSON.parse(data); + } catch(e) { + throw errors.InvalidResponse(data); + } + + return result; + + } else { + throw new Error('You tried to send "'+ payload.method +'" synchronously. Synchronous requests are not supported by the IPC provider.'); + } +}; + +IpcProvider.prototype.sendAsync = function (payload, callback) { + // try reconnect, when connection is gone + if(!this.connection.writable) + this.connection.connect({path: this.path}); + + + this.connection.write(JSON.stringify(payload)); + this._addResponseCallback(payload, callback); +}; + +module.exports = IpcProvider; + diff --git a/libjsqrc/ethereumjs/lib/web3/method.js b/libjsqrc/ethereumjs/lib/web3/method.js index 8f10b2dfe..7b15a34ba 100644 --- a/libjsqrc/ethereumjs/lib/web3/method.js +++ b/libjsqrc/ethereumjs/lib/web3/method.js @@ -94,7 +94,7 @@ Method.prototype.formatInput = function (args) { * @return {Object} */ Method.prototype.formatOutput = function (result) { - return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; + return this.outputFormatter && result ? this.outputFormatter(result) : result; }; /** diff --git a/libjsqrc/ethereumjs/lib/web3/property.js b/libjsqrc/ethereumjs/lib/web3/property.js index a2e7282e9..3eb1a0057 100644 --- a/libjsqrc/ethereumjs/lib/web3/property.js +++ b/libjsqrc/ethereumjs/lib/web3/property.js @@ -22,6 +22,7 @@ */ var RequestManager = require('./requestmanager'); +var utils = require('../utils/utils'); var Property = function (options) { this.name = options.name; @@ -53,6 +54,19 @@ Property.prototype.formatOutput = function (result) { return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; }; +/** + * Should be used to extract callback from array of arguments. Modifies input param + * + * @method extractCallback + * @param {Array} arguments + * @return {Function|Null} callback, if exists + */ +Property.prototype.extractCallback = function (args) { + if (utils.isFunction(args[args.length - 1])) { + return args.pop(); // modify the args array! + } +}; + /** * Should attach function to method * @@ -79,7 +93,10 @@ Property.prototype.attachToObject = function (obj) { return prefix + name.charAt(0).toUpperCase() + name.slice(1); }; - obj[toAsyncName('get', name)] = this.getAsync.bind(this); + var func = this.getAsync.bind(this); + func.request = this.request.bind(this); + + obj[toAsyncName('get', name)] = func; }; /** @@ -112,5 +129,22 @@ Property.prototype.getAsync = function (callback) { }); }; +/** + * Should be called to create pure JSONRPC request which can be used in batch request + * + * @method request + * @param {...} params + * @return {Object} jsonrpc request + */ +Property.prototype.request = function () { + var payload = { + method: this.getter, + params: [], + callback: this.extractCallback(Array.prototype.slice.call(arguments)) + }; + payload.format = this.formatOutput.bind(this); + return payload; +}; + module.exports = Property; diff --git a/libjsqrc/ethereumjs/lib/web3/qtsync.js b/libjsqrc/ethereumjs/lib/web3/qtsync.js deleted file mode 100644 index 75dcb43ab..000000000 --- a/libjsqrc/ethereumjs/lib/web3/qtsync.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file qtsync.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * @date 2014 - */ - -var QtSyncProvider = function () { -}; - -QtSyncProvider.prototype.send = function (payload) { - var result = navigator.qt.callMethod(JSON.stringify(payload)); - return JSON.parse(result); -}; - -module.exports = QtSyncProvider; - diff --git a/libjsqrc/ethereumjs/package.js b/libjsqrc/ethereumjs/package.js index e46e9cbc6..e37f23f70 100644 --- a/libjsqrc/ethereumjs/package.js +++ b/libjsqrc/ethereumjs/package.js @@ -1,7 +1,7 @@ /* jshint ignore:start */ Package.describe({ name: 'ethereum:web3', - version: '0.7.1', + version: '0.9.0', summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC', git: 'https://github.com/ethereum/ethereum.js', // By default, Meteor will default to using README.md for documentation. diff --git a/libjsqrc/ethereumjs/package.json b/libjsqrc/ethereumjs/package.json index 52b1be15d..519977095 100644 --- a/libjsqrc/ethereumjs/package.json +++ b/libjsqrc/ethereumjs/package.json @@ -1,7 +1,7 @@ { "name": "web3", "namespace": "ethereum", - "version": "0.7.1", + "version": "0.9.0", "description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC", "main": "./index.js", "directories": { @@ -56,30 +56,30 @@ ], "author": "ethdev.com", "authors": [ - { - "name": "Jeffery Wilcke", - "email": "jeff@ethdev.com", - "url": "https://github.com/obscuren" - }, { "name": "Marek Kotewicz", "email": "marek@ethdev.com", "url": "https://github.com/debris" }, + { + "name": "Fabian Vogelsteller", + "email": "fabian@ethdev.com", + "homepage": "http://frozeman.de" + }, { "name": "Marian Oancea", "email": "marian@ethdev.com", "url": "https://github.com/cubedro" }, - { - "name": "Fabian Vogelsteller", - "email": "fabian@frozeman.de", - "homepage": "http://frozeman.de" - }, { "name": "Gav Wood", "email": "g@ethdev.com", "homepage": "http://gavwood.com" + }, + { + "name": "Jeffery Wilcke", + "email": "jeff@ethdev.com", + "url": "https://github.com/obscuren" } ], "license": "LGPL-3.0" diff --git a/libjsqrc/ethereumjs/styleguide.md b/libjsqrc/ethereumjs/styleguide.md new file mode 100644 index 000000000..9140ca9ed --- /dev/null +++ b/libjsqrc/ethereumjs/styleguide.md @@ -0,0 +1,1741 @@ +[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +# Airbnb JavaScript Style Guide() { + +*A mostly reasonable approach to JavaScript* + + +## Table of Contents + + 1. [Types](#types) + 1. [Objects](#objects) + 1. [Arrays](#arrays) + 1. [Strings](#strings) + 1. [Functions](#functions) + 1. [Properties](#properties) + 1. [Variables](#variables) + 1. [Hoisting](#hoisting) + 1. [Comparison Operators & Equality](#comparison-operators--equality) + 1. [Blocks](#blocks) + 1. [Comments](#comments) + 1. [Whitespace](#whitespace) + 1. [Commas](#commas) + 1. [Semicolons](#semicolons) + 1. [Type Casting & Coercion](#type-casting--coercion) + 1. [Naming Conventions](#naming-conventions) + 1. [Accessors](#accessors) + 1. [Constructors](#constructors) + 1. [Events](#events) + 1. [Modules](#modules) + 1. [jQuery](#jquery) + 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) + 1. [Testing](#testing) + 1. [Performance](#performance) + 1. [Resources](#resources) + 1. [In the Wild](#in-the-wild) + 1. [Translation](#translation) + 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) + 1. [Chat With Us About Javascript](#chat-with-us-about-javascript) + 1. [Contributors](#contributors) + 1. [License](#license) + +## Types + + - **Primitives**: When you access a primitive type you work directly on its value. + + + `string` + + `number` + + `boolean` + + `null` + + `undefined` + + ```javascript + var foo = 1; + var bar = foo; + + bar = 9; + + console.log(foo, bar); // => 1, 9 + ``` + - **Complex**: When you access a complex type you work on a reference to its value. + + + `object` + + `array` + + `function` + + ```javascript + var foo = [1, 2]; + var bar = foo; + + bar[0] = 9; + + console.log(foo[0], bar[0]); // => 9, 9 + ``` + +**[⬆ back to top](#table-of-contents)** + +## Objects + + - Use the literal syntax for object creation. + + ```javascript + // bad + var item = new Object(); + + // good + var item = {}; + ``` + + - Don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). + + ```javascript + // bad + var superman = { + default: { clark: 'kent' }, + private: true + }; + + // good + var superman = { + defaults: { clark: 'kent' }, + hidden: true + }; + ``` + + - Use readable synonyms in place of reserved words. + + ```javascript + // bad + var superman = { + class: 'alien' + }; + + // bad + var superman = { + klass: 'alien' + }; + + // good + var superman = { + type: 'alien' + }; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Arrays + + - Use the literal syntax for array creation. + + ```javascript + // bad + var items = new Array(); + + // good + var items = []; + ``` + + - Use Array#push instead of direct assignment to add items to an array. + + ```javascript + var someStack = []; + + + // bad + someStack[someStack.length] = 'abracadabra'; + + // good + someStack.push('abracadabra'); + ``` + + - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) + + ```javascript + var len = items.length; + var itemsCopy = []; + var i; + + // bad + for (i = 0; i < len; i++) { + itemsCopy[i] = items[i]; + } + + // good + itemsCopy = items.slice(); + ``` + + - To convert an array-like object to an array, use Array#slice. + + ```javascript + function trigger() { + var args = Array.prototype.slice.call(arguments); + ... + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Strings + + - Use single quotes `''` for strings. + + ```javascript + // bad + var name = "Bob Parr"; + + // good + var name = 'Bob Parr'; + + // bad + var fullName = "Bob " + this.lastName; + + // good + var fullName = 'Bob ' + this.lastName; + ``` + + - Strings longer than 80 characters should be written across multiple lines using string concatenation. + - Note: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40). + + ```javascript + // bad + var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; + + // bad + var errorMessage = 'This is a super long error that was thrown because \ + of Batman. When you stop to think about how Batman had anything to do \ + with this, you would get nowhere \ + fast.'; + + // good + var errorMessage = 'This is a super long error that was thrown because ' + + 'of Batman. When you stop to think about how Batman had anything to do ' + + 'with this, you would get nowhere fast.'; + ``` + + - When programmatically building up a string, use Array#join instead of string concatenation. Mostly for IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2). + + ```javascript + var items; + var messages; + var length; + var i; + + messages = [{ + state: 'success', + message: 'This one worked.' + }, { + state: 'success', + message: 'This one worked as well.' + }, { + state: 'error', + message: 'This one did not work.' + }]; + + length = messages.length; + + // bad + function inbox(messages) { + items = '
    '; + + for (i = 0; i < length; i++) { + items += '
  • ' + messages[i].message + '
  • '; + } + + return items + '
'; + } + + // good + function inbox(messages) { + items = []; + + for (i = 0; i < length; i++) { + // use direct assignment in this case because we're micro-optimizing. + items[i] = '
  • ' + messages[i].message + '
  • '; + } + + return '
      ' + items.join('') + '
    '; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Functions + + - Function expressions: + + ```javascript + // anonymous function expression + var anonymous = function() { + return true; + }; + + // named function expression + var named = function named() { + return true; + }; + + // immediately-invoked function expression (IIFE) + (function() { + console.log('Welcome to the Internet. Please follow me.'); + })(); + ``` + + - Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. + - **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). + + ```javascript + // bad + if (currentUser) { + function test() { + console.log('Nope.'); + } + } + + // good + var test; + if (currentUser) { + test = function test() { + console.log('Yup.'); + }; + } + ``` + + - Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. + + ```javascript + // bad + function nope(name, options, arguments) { + // ...stuff... + } + + // good + function yup(name, options, args) { + // ...stuff... + } + ``` + +**[⬆ back to top](#table-of-contents)** + + + +## Properties + + - Use dot notation when accessing properties. + + ```javascript + var luke = { + jedi: true, + age: 28 + }; + + // bad + var isJedi = luke['jedi']; + + // good + var isJedi = luke.jedi; + ``` + + - Use subscript notation `[]` when accessing properties with a variable. + + ```javascript + var luke = { + jedi: true, + age: 28 + }; + + function getProp(prop) { + return luke[prop]; + } + + var isJedi = getProp('jedi'); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Variables + + - Always use `var` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. + + ```javascript + // bad + superPower = new SuperPower(); + + // good + var superPower = new SuperPower(); + ``` + + - Use one `var` declaration per variable. + It's easier to add new variable declarations this way, and you never have + to worry about swapping out a `;` for a `,` or introducing punctuation-only + diffs. + + ```javascript + // bad + var items = getItems(), + goSportsTeam = true, + dragonball = 'z'; + + // bad + // (compare to above, and try to spot the mistake) + var items = getItems(), + goSportsTeam = true; + dragonball = 'z'; + + // good + var items = getItems(); + var goSportsTeam = true; + var dragonball = 'z'; + ``` + + - Declare unassigned variables last. This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables. + + ```javascript + // bad + var i, len, dragonball, + items = getItems(), + goSportsTeam = true; + + // bad + var i; + var items = getItems(); + var dragonball; + var goSportsTeam = true; + var len; + + // good + var items = getItems(); + var goSportsTeam = true; + var dragonball; + var length; + var i; + ``` + + - Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues. + + ```javascript + // bad + function() { + test(); + console.log('doing stuff..'); + + //..other stuff.. + + var name = getName(); + + if (name === 'test') { + return false; + } + + return name; + } + + // good + function() { + var name = getName(); + + test(); + console.log('doing stuff..'); + + //..other stuff.. + + if (name === 'test') { + return false; + } + + return name; + } + + // bad - unnecessary function call + function() { + var name = getName(); + + if (!arguments.length) { + return false; + } + + this.setFirstName(name); + + return true; + } + + // good + function() { + var name; + + if (!arguments.length) { + return false; + } + + name = getName(); + this.setFirstName(name); + + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Hoisting + + - Variable declarations get hoisted to the top of their scope, but their assignment does not. + + ```javascript + // we know this wouldn't work (assuming there + // is no notDefined global variable) + function example() { + console.log(notDefined); // => throws a ReferenceError + } + + // creating a variable declaration after you + // reference the variable will work due to + // variable hoisting. Note: the assignment + // value of `true` is not hoisted. + function example() { + console.log(declaredButNotAssigned); // => undefined + var declaredButNotAssigned = true; + } + + // The interpreter is hoisting the variable + // declaration to the top of the scope, + // which means our example could be rewritten as: + function example() { + var declaredButNotAssigned; + console.log(declaredButNotAssigned); // => undefined + declaredButNotAssigned = true; + } + ``` + + - Anonymous function expressions hoist their variable name, but not the function assignment. + + ```javascript + function example() { + console.log(anonymous); // => undefined + + anonymous(); // => TypeError anonymous is not a function + + var anonymous = function() { + console.log('anonymous function expression'); + }; + } + ``` + + - Named function expressions hoist the variable name, not the function name or the function body. + + ```javascript + function example() { + console.log(named); // => undefined + + named(); // => TypeError named is not a function + + superPower(); // => ReferenceError superPower is not defined + + var named = function superPower() { + console.log('Flying'); + }; + } + + // the same is true when the function name + // is the same as the variable name. + function example() { + console.log(named); // => undefined + + named(); // => TypeError named is not a function + + var named = function named() { + console.log('named'); + } + } + ``` + + - Function declarations hoist their name and the function body. + + ```javascript + function example() { + superPower(); // => Flying + + function superPower() { + console.log('Flying'); + } + } + ``` + + - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/). + +**[⬆ back to top](#table-of-contents)** + + + +## Comparison Operators & Equality + + - Use `===` and `!==` over `==` and `!=`. + - Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: + + + **Objects** evaluate to **true** + + **Undefined** evaluates to **false** + + **Null** evaluates to **false** + + **Booleans** evaluate to **the value of the boolean** + + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** + + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** + + ```javascript + if ([0]) { + // true + // An array is an object, objects evaluate to true + } + ``` + + - Use shortcuts. + + ```javascript + // bad + if (name !== '') { + // ...stuff... + } + + // good + if (name) { + // ...stuff... + } + + // bad + if (collection.length > 0) { + // ...stuff... + } + + // good + if (collection.length) { + // ...stuff... + } + ``` + + - For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. + +**[⬆ back to top](#table-of-contents)** + + +## Blocks + + - Use braces with all multi-line blocks. + + ```javascript + // bad + if (test) + return false; + + // good + if (test) return false; + + // good + if (test) { + return false; + } + + // bad + function() { return false; } + + // good + function() { + return false; + } + ``` + + - If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your + `if` block's closing brace. + + ```javascript + // bad + if (test) { + thing1(); + thing2(); + } + else { + thing3(); + } + + // good + if (test) { + thing1(); + thing2(); + } else { + thing3(); + } + ``` + + +**[⬆ back to top](#table-of-contents)** + + +## Comments + + - Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. + + ```javascript + // bad + // make() returns a new element + // based on the passed in tag name + // + // @param {String} tag + // @return {Element} element + function make(tag) { + + // ...stuff... + + return element; + } + + // good + /** + * make() returns a new element + * based on the passed in tag name + * + * @param {String} tag + * @return {Element} element + */ + function make(tag) { + + // ...stuff... + + return element; + } + ``` + + - Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment. + + ```javascript + // bad + var active = true; // is current tab + + // good + // is current tab + var active = true; + + // bad + function getType() { + console.log('fetching type...'); + // set the default type to 'no type' + var type = this._type || 'no type'; + + return type; + } + + // good + function getType() { + console.log('fetching type...'); + + // set the default type to 'no type' + var type = this._type || 'no type'; + + return type; + } + ``` + + - Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME -- need to figure this out` or `TODO -- need to implement`. + + - Use `// FIXME:` to annotate problems. + + ```javascript + function Calculator() { + + // FIXME: shouldn't use a global here + total = 0; + + return this; + } + ``` + + - Use `// TODO:` to annotate solutions to problems. + + ```javascript + function Calculator() { + + // TODO: total should be configurable by an options param + this.total = 0; + + return this; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Whitespace + + - Use soft tabs set to 4 spaces. + + ```javascript + // good + function() { + ∙∙∙∙var name; + } + + // bad + function() { + ∙var name; + } + + // bad + function() { + ∙∙var name; + } + ``` + + - Place 1 space before the leading brace. + + ```javascript + // bad + function test(){ + console.log('test'); + } + + // good + function test() { + console.log('test'); + } + + // bad + dog.set('attr',{ + age: '1 year', + breed: 'Bernese Mountain Dog' + }); + + // good + dog.set('attr', { + age: '1 year', + breed: 'Bernese Mountain Dog' + }); + ``` + + - Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space before the argument list in function calls and declarations. + + ```javascript + // bad + if(isJedi) { + fight (); + } + + // good + if (isJedi) { + fight(); + } + + // bad + function fight () { + console.log ('Swooosh!'); + } + + // good + function fight() { + console.log('Swooosh!'); + } + ``` + + - Set off operators with spaces. + + ```javascript + // bad + var x=y+5; + + // good + var x = y + 5; + ``` + + - End files with a single newline character. + + ```javascript + // bad + (function(global) { + // ...stuff... + })(this); + ``` + + ```javascript + // bad + (function(global) { + // ...stuff... + })(this);↵ + ↵ + ``` + + ```javascript + // good + (function(global) { + // ...stuff... + })(this);↵ + ``` + + - Use indentation when making long method chains. Use a leading dot, which + emphasizes that the line is a method call, not a new statement. + + ```javascript + // bad + $('#items').find('.selected').highlight().end().find('.open').updateCount(); + + // bad + $('#items'). + find('.selected'). + highlight(). + end(). + find('.open'). + updateCount(); + + // good + $('#items') + .find('.selected') + .highlight() + .end() + .find('.open') + .updateCount(); + + // bad + var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) + .attr('width', (radius + margin) * 2).append('svg:g') + .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') + .call(tron.led); + + // good + var leds = stage.selectAll('.led') + .data(data) + .enter().append('svg:svg') + .classed('led', true) + .attr('width', (radius + margin) * 2) + .append('svg:g') + .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') + .call(tron.led); + ``` + + - Leave a blank line after blocks and before the next statement + + ```javascript + // bad + if (foo) { + return bar; + } + return baz; + + // good + if (foo) { + return bar; + } + + return baz; + + // bad + var obj = { + foo: function() { + }, + bar: function() { + } + }; + return obj; + + // good + var obj = { + foo: function() { + }, + + bar: function() { + } + }; + + return obj; + ``` + + +**[⬆ back to top](#table-of-contents)** + +## Commas + + - Leading commas: **Nope.** + + ```javascript + // bad + var story = [ + once + , upon + , aTime + ]; + + // good + var story = [ + once, + upon, + aTime + ]; + + // bad + var hero = { + firstName: 'Bob' + , lastName: 'Parr' + , heroName: 'Mr. Incredible' + , superPower: 'strength' + }; + + // good + var hero = { + firstName: 'Bob', + lastName: 'Parr', + heroName: 'Mr. Incredible', + superPower: 'strength' + }; + ``` + + - Additional trailing comma: **Nope.** This can cause problems with IE6/7 and IE9 if it's in quirksmode. Also, in some implementations of ES3 would add length to an array if it had an additional trailing comma. This was clarified in ES5 ([source](http://es5.github.io/#D)): + + > Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this. + + ```javascript + // bad + var hero = { + firstName: 'Kevin', + lastName: 'Flynn', + }; + + var heroes = [ + 'Batman', + 'Superman', + ]; + + // good + var hero = { + firstName: 'Kevin', + lastName: 'Flynn' + }; + + var heroes = [ + 'Batman', + 'Superman' + ]; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Semicolons + + - **Yup.** + + ```javascript + // bad + (function() { + var name = 'Skywalker' + return name + })() + + // good + (function() { + var name = 'Skywalker'; + return name; + })(); + + // good (guards against the function becoming an argument when two files with IIFEs are concatenated) + ;(function() { + var name = 'Skywalker'; + return name; + })(); + ``` + + [Read more](http://stackoverflow.com/a/7365214/1712802). + +**[⬆ back to top](#table-of-contents)** + + +## Type Casting & Coercion + + - Perform type coercion at the beginning of the statement. + - Strings: + + ```javascript + // => this.reviewScore = 9; + + // bad + var totalScore = this.reviewScore + ''; + + // good + var totalScore = '' + this.reviewScore; + + // bad + var totalScore = '' + this.reviewScore + ' total score'; + + // good + var totalScore = this.reviewScore + ' total score'; + ``` + + - Use `parseInt` for Numbers and always with a radix for type casting. + + ```javascript + var inputValue = '4'; + + // bad + var val = new Number(inputValue); + + // bad + var val = +inputValue; + + // bad + var val = inputValue >> 0; + + // bad + var val = parseInt(inputValue); + + // good + var val = Number(inputValue); + + // good + var val = parseInt(inputValue, 10); + ``` + + - If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. + + ```javascript + // good + /** + * parseInt was the reason my code was slow. + * Bitshifting the String to coerce it to a + * Number made it a lot faster. + */ + var val = inputValue >> 0; + ``` + + - **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but Bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: + + ```javascript + 2147483647 >> 0 //=> 2147483647 + 2147483648 >> 0 //=> -2147483648 + 2147483649 >> 0 //=> -2147483647 + ``` + + - Booleans: + + ```javascript + var age = 0; + + // bad + var hasAge = new Boolean(age); + + // good + var hasAge = Boolean(age); + + // good + var hasAge = !!age; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Naming Conventions + + - Avoid single letter names. Be descriptive with your naming. + + ```javascript + // bad + function q() { + // ...stuff... + } + + // good + function query() { + // ..stuff.. + } + ``` + + - Use camelCase when naming objects, functions, and instances. + + ```javascript + // bad + var OBJEcttsssss = {}; + var this_is_my_object = {}; + var o = {}; + function c() {} + + // good + var thisIsMyObject = {}; + function thisIsMyFunction() {} + ``` + + - Use PascalCase when naming constructors or classes. + + ```javascript + // bad + function user(options) { + this.name = options.name; + } + + var bad = new user({ + name: 'nope' + }); + + // good + function User(options) { + this.name = options.name; + } + + var good = new User({ + name: 'yup' + }); + ``` + + - Use a leading underscore `_` when naming private properties. + + ```javascript + // bad + this.__firstName__ = 'Panda'; + this.firstName_ = 'Panda'; + + // good + this._firstName = 'Panda'; + ``` + + - When saving a reference to `this` use `_this`. + + ```javascript + // bad + function() { + var self = this; + return function() { + console.log(self); + }; + } + + // bad + function() { + var that = this; + return function() { + console.log(that); + }; + } + + // good + function() { + var _this = this; + return function() { + console.log(_this); + }; + } + ``` + + - Name your functions. This is helpful for stack traces. + + ```javascript + // bad + var log = function(msg) { + console.log(msg); + }; + + // good + var log = function log(msg) { + console.log(msg); + }; + ``` + + - **Note:** IE8 and below exhibit some quirks with named function expressions. See [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/) for more info. + + - If your file exports a single class, your filename should be exactly the name of the class. + ```javascript + // file contents + class CheckBox { + // ... + } + module.exports = CheckBox; + + // in some other file + // bad + var CheckBox = require('./checkBox'); + + // bad + var CheckBox = require('./check_box'); + + // good + var CheckBox = require('./CheckBox'); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Accessors + + - Accessor functions for properties are not required. + - If you do make accessor functions use getVal() and setVal('hello'). + + ```javascript + // bad + dragon.age(); + + // good + dragon.getAge(); + + // bad + dragon.age(25); + + // good + dragon.setAge(25); + ``` + + - If the property is a boolean, use isVal() or hasVal(). + + ```javascript + // bad + if (!dragon.age()) { + return false; + } + + // good + if (!dragon.hasAge()) { + return false; + } + ``` + + - It's okay to create get() and set() functions, but be consistent. + + ```javascript + function Jedi(options) { + options || (options = {}); + var lightsaber = options.lightsaber || 'blue'; + this.set('lightsaber', lightsaber); + } + + Jedi.prototype.set = function(key, val) { + this[key] = val; + }; + + Jedi.prototype.get = function(key) { + return this[key]; + }; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Constructors + + - Assign methods to the prototype object, instead of overwriting the prototype with a new object. Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base! + + ```javascript + function Jedi() { + console.log('new jedi'); + } + + // bad + Jedi.prototype = { + fight: function fight() { + console.log('fighting'); + }, + + block: function block() { + console.log('blocking'); + } + }; + + // good + Jedi.prototype.fight = function fight() { + console.log('fighting'); + }; + + Jedi.prototype.block = function block() { + console.log('blocking'); + }; + ``` + + - Methods can return `this` to help with method chaining. + + ```javascript + // bad + Jedi.prototype.jump = function() { + this.jumping = true; + return true; + }; + + Jedi.prototype.setHeight = function(height) { + this.height = height; + }; + + var luke = new Jedi(); + luke.jump(); // => true + luke.setHeight(20); // => undefined + + // good + Jedi.prototype.jump = function() { + this.jumping = true; + return this; + }; + + Jedi.prototype.setHeight = function(height) { + this.height = height; + return this; + }; + + var luke = new Jedi(); + + luke.jump() + .setHeight(20); + ``` + + + - It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. + + ```javascript + function Jedi(options) { + options || (options = {}); + this.name = options.name || 'no name'; + } + + Jedi.prototype.getName = function getName() { + return this.name; + }; + + Jedi.prototype.toString = function toString() { + return 'Jedi - ' + this.getName(); + }; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Events + + - When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: + + ```js + // bad + $(this).trigger('listingUpdated', listing.id); + + ... + + $(this).on('listingUpdated', function(e, listingId) { + // do something with listingId + }); + ``` + + prefer: + + ```js + // good + $(this).trigger('listingUpdated', { listingId : listing.id }); + + ... + + $(this).on('listingUpdated', function(e, data) { + // do something with data.listingId + }); + ``` + + **[⬆ back to top](#table-of-contents)** + + +## Modules + + - The module should start with a `!`. This ensures that if a malformed module forgets to include a final semicolon there aren't errors in production when the scripts get concatenated. [Explanation](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933) + - The file should be named with camelCase, live in a folder with the same name, and match the name of the single export. + - Add a method called `noConflict()` that sets the exported module to the previous version and returns this one. + - Always declare `'use strict';` at the top of the module. + + ```javascript + // fancyInput/fancyInput.js + + !function(global) { + 'use strict'; + + var previousFancyInput = global.FancyInput; + + function FancyInput(options) { + this.options = options || {}; + } + + FancyInput.noConflict = function noConflict() { + global.FancyInput = previousFancyInput; + return FancyInput; + }; + + global.FancyInput = FancyInput; + }(this); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## jQuery + + - Prefix jQuery object variables with a `$`. + + ```javascript + // bad + var sidebar = $('.sidebar'); + + // good + var $sidebar = $('.sidebar'); + ``` + + - Cache jQuery lookups. + + ```javascript + // bad + function setSidebar() { + $('.sidebar').hide(); + + // ...stuff... + + $('.sidebar').css({ + 'background-color': 'pink' + }); + } + + // good + function setSidebar() { + var $sidebar = $('.sidebar'); + $sidebar.hide(); + + // ...stuff... + + $sidebar.css({ + 'background-color': 'pink' + }); + } + ``` + + - For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) + - Use `find` with scoped jQuery object queries. + + ```javascript + // bad + $('ul', '.sidebar').hide(); + + // bad + $('.sidebar').find('ul').hide(); + + // good + $('.sidebar ul').hide(); + + // good + $('.sidebar > ul').hide(); + + // good + $sidebar.find('ul').hide(); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## ECMAScript 5 Compatibility + + - Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). + +**[⬆ back to top](#table-of-contents)** + + +## Testing + + - **Yup.** + + ```javascript + function() { + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Performance + + - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) + - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) + - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) + - [Bang Function](http://jsperf.com/bang-function) + - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) + - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) + - [Long String Concatenation](http://jsperf.com/ya-string-concat) + - Loading... + +**[⬆ back to top](#table-of-contents)** + + +## Resources + + +**Read This** + + - [Annotated ECMAScript 5.1](http://es5.github.com/) + +**Tools** + + - Code Style Linters + + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc) + + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) + +**Other Style Guides** + + - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) + - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) + - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) + - [JavaScript Standard Style](https://github.com/feross/standard) + +**Other Styles** + + - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen + - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen + - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun + - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman + +**Further Reading** + + - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll + - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer + - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz + - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban + - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock + +**Books** + + - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford + - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov + - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz + - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders + - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas + - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw + - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig + - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch + - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault + - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg + - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy + - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon + - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov + - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman + - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke + - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson + +**Blogs** + + - [DailyJS](http://dailyjs.com/) + - [JavaScript Weekly](http://javascriptweekly.com/) + - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) + - [Bocoup Weblog](http://weblog.bocoup.com/) + - [Adequately Good](http://www.adequatelygood.com/) + - [NCZOnline](http://www.nczonline.net/) + - [Perfection Kills](http://perfectionkills.com/) + - [Ben Alman](http://benalman.com/) + - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) + - [Dustin Diaz](http://dustindiaz.com/) + - [nettuts](http://net.tutsplus.com/?s=javascript) + +**Podcasts** + + - [JavaScript Jabber](http://devchat.tv/js-jabber/) + + +**[⬆ back to top](#table-of-contents)** + +## In the Wild + + This is a list of organizations that are using this style guide. Send us a pull request or open an issue and we'll add you to the list. + + - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) + - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) + - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) + - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) + - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) + - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) + - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) + - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) + - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) + - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) + - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) + - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) + - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) + - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) + - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) + - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) + - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) + - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide) + - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) + - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) + - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) + - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript) + - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) + - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) + - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) + - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript) + - **Muber**: [muber/javascript](https://github.com/muber/javascript) + - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) + - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) + - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) + - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript) + - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) + - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) + - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) + - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) + - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) + - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) + - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide) + - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) + - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript) + - **Target**: [target/javascript](https://github.com/target/javascript) + - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript) + - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript) + - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) + - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) + - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) + - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) + +## Translation + + This style guide is also available in other languages: + + - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) + - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) + - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) + - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) + - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese(Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide) + - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) + - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) + - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) + - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) + - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) + - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) + - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) + - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) + - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) + +## The JavaScript Style Guide Guide + + - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) + +## Chat With Us About JavaScript + + - Find us on [gitter](https://gitter.im/airbnb/javascript). + +## Contributors + + - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) + + +## License + +(The MIT License) + +Copyright (c) 2014 Airbnb + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**[⬆ back to top](#table-of-contents)** + +# }; diff --git a/libjsqrc/ethereumjs/test/batch.js b/libjsqrc/ethereumjs/test/batch.js index 5a06f0e7b..a91bae2ac 100644 --- a/libjsqrc/ethereumjs/test/batch.js +++ b/libjsqrc/ethereumjs/test/batch.js @@ -44,7 +44,45 @@ describe('lib/web3/batch', function () { batch.execute(); }); - it('should execute batch request', function (done) { + it('should execute batch request for async properties', function (done) { + + var provider = new FakeHttpProvider(); + web3.setProvider(provider); + web3.reset(); + + var result = []; + var result2 = '0xb'; + provider.injectBatchResults([result, result2]); + + var counter = 0; + var callback = function (err, r) { + counter++; + assert.isArray(result, r); + }; + + var callback2 = function (err, r) { + assert.equal(counter, 1); + assert.equal(r, 11); + done(); + }; + + provider.injectValidation(function (payload) { + var first = payload[0]; + var second = payload[1]; + + assert.equal(first.method, 'eth_accounts'); + assert.deepEqual(first.params, []); + assert.equal(second.method, 'net_peerCount'); + assert.deepEqual(second.params, []); + }); + + var batch = web3.createBatch(); + batch.add(web3.eth.getAccounts.request(callback)); + batch.add(web3.net.getPeerCount.request(callback2)); + batch.execute(); + }); + + it('should execute batch request with contract', function (done) { var provider = new FakeHttpProvider(); web3.setProvider(provider); @@ -100,6 +138,64 @@ describe('lib/web3/batch', function () { provider.injectBatchResults([result, result2]); batch.execute(); }); + + it('should execute batch requests and receive errors', function (done) { + + var provider = new FakeHttpProvider(); + web3.setProvider(provider); + web3.reset(); + + var abi = [{ + "name": "balance(address)", + "type": "function", + "inputs": [{ + "name": "who", + "type": "address" + }], + "constant": true, + "outputs": [{ + "name": "value", + "type": "uint256" + }] + }]; + + + var address = '0x1000000000000000000000000000000000000001'; + var result = 'Something went wrong'; + var result2 = 'Something went wrong 2'; + + + var counter = 0; + var callback = function (err, r) { + counter++; + assert.isNotNull(err); + }; + + var callback2 = function (err, r) { + assert.equal(counter, 1); + assert.isNotNull(err); + done(); + }; + + provider.injectValidation(function (payload) { + var first = payload[0]; + var second = payload[1]; + + assert.equal(first.method, 'eth_getBalance'); + assert.deepEqual(first.params, ['0x0000000000000000000000000000000000000000', 'latest']); + assert.equal(second.method, 'eth_call'); + assert.deepEqual(second.params, [{ + 'to': '0x1000000000000000000000000000000000000001', + 'data': '0xe3d670d70000000000000000000000001000000000000000000000000000000000000001' + }]); + }); + + var batch = web3.createBatch(); + batch.add(web3.eth.getBalance.request('0x0000000000000000000000000000000000000000', 'latest', callback)); + batch.add(web3.eth.contract(abi).at(address).balance.request(address, callback2)); + provider.injectBatchResults([result, result2], true); // injects error + batch.execute(); + }); }); }); diff --git a/libjsqrc/ethereumjs/test/contract.js b/libjsqrc/ethereumjs/test/contract.js index 71ac20701..7e6cbf7e3 100644 --- a/libjsqrc/ethereumjs/test/contract.js +++ b/libjsqrc/ethereumjs/test/contract.js @@ -209,13 +209,7 @@ describe('web3.eth.contract', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_newFilter'); assert.deepEqual(payload.params[0], { - topics: [ - null, - null, - null, - null, - null - ], + topics: [], address: '0x1234567890123456789012345678901234567890' }); } else if (step === 1) { diff --git a/libjsqrc/ethereumjs/test/errors.js b/libjsqrc/ethereumjs/test/errors.js new file mode 100644 index 000000000..3ed3c8505 --- /dev/null +++ b/libjsqrc/ethereumjs/test/errors.js @@ -0,0 +1,17 @@ +var chai = require('chai'); +var assert = chai.assert; +var errors = require('../lib/web3/errors'); + +describe('lib/web3/method', function () { + describe('getCall', function () { + + for(var key in errors) { + it('should return and error', function () { + + assert.instanceOf(errors[key](), Error); + }); + } + + }); +}); + diff --git a/libjsqrc/ethereumjs/test/event.encode.js b/libjsqrc/ethereumjs/test/event.encode.js index 6d9850c00..469a5929e 100644 --- a/libjsqrc/ethereumjs/test/event.encode.js +++ b/libjsqrc/ethereumjs/test/event.encode.js @@ -184,6 +184,7 @@ var tests = [{ }, options: {}, expected: { + address: address, topics: [ '0x0000000000000000000000000000000000000000000000000000000000000001' ] @@ -207,6 +208,7 @@ var tests = [{ }, options: {}, expected: { + address: address, topics: [ null, '0x0000000000000000000000000000000000000000000000000000000000000001' diff --git a/libjsqrc/ethereumjs/test/helpers/FakeHttpProvider.js b/libjsqrc/ethereumjs/test/helpers/FakeHttpProvider.js index 0b01a171c..1e6ce1252 100644 --- a/libjsqrc/ethereumjs/test/helpers/FakeHttpProvider.js +++ b/libjsqrc/ethereumjs/test/helpers/FakeHttpProvider.js @@ -10,6 +10,17 @@ var getResponseStub = function () { }; }; +var getErrorStub = function () { + return { + jsonrpc: '2.0', + id: 1, + error: { + code: 1234, + message: '' + } + }; +}; + var FakeHttpProvider = function () { this.response = getResponseStub(); this.error = null; @@ -48,10 +59,15 @@ FakeHttpProvider.prototype.injectResult = function (result) { this.response.result = result; }; -FakeHttpProvider.prototype.injectBatchResults = function (results) { +FakeHttpProvider.prototype.injectBatchResults = function (results, error) { this.response = results.map(function (r) { - var response = getResponseStub(); - response.result = r; + if(error) { + var response = getErrorStub(); + response.error.message = r; + } else { + var response = getResponseStub(); + response.result = r; + } return response; }); }; diff --git a/libjsqrc/ethereumjs/test/helpers/FakeIpcRequest.js b/libjsqrc/ethereumjs/test/helpers/FakeIpcRequest.js new file mode 100644 index 000000000..2226b3528 --- /dev/null +++ b/libjsqrc/ethereumjs/test/helpers/FakeIpcRequest.js @@ -0,0 +1,41 @@ +var chai = require('chai'); +var assert = chai.assert; + +var FakeIpcRequest = function () { + this._handle = {fd: {}}; + this.callbacks = []; + + return this +}; + +FakeIpcRequest.prototype.connect = function (path) { + assert.notEqual(path, undefined); + + return this; +}; + +FakeIpcRequest.prototype.on = function(name, callback) { + if(name === 'data'){ + this.callbacks.push(callback); + } +}; + +FakeIpcRequest.prototype.writeSync = function (payload) { + assert.equal(typeof payload, 'string'); + + return payload; +}; + +FakeIpcRequest.prototype.write = function (payload) { + assert.equal(typeof payload, 'string'); + + this.callbacks.forEach(function(cb){ + setTimeout(function(){ + cb(payload); + }, 100); + }); + +}; + +module.exports = new FakeIpcRequest(); + diff --git a/libjsqrc/ethereumjs/test/httpprovider.js b/libjsqrc/ethereumjs/test/httpprovider.js index 6205a16d2..979b2be8f 100644 --- a/libjsqrc/ethereumjs/test/httpprovider.js +++ b/libjsqrc/ethereumjs/test/httpprovider.js @@ -29,5 +29,13 @@ describe('lib/web3/httpprovider', function () { }); }); }); + + describe('isConnected', function () { + it('should return a boolean', function () { + var provider = new HttpProvider(); + + assert.isBoolean(provider.isConnected()); + }); + }); }); diff --git a/libjsqrc/ethereumjs/test/ipcprovider.js b/libjsqrc/ethereumjs/test/ipcprovider.js new file mode 100644 index 000000000..5d729a6d2 --- /dev/null +++ b/libjsqrc/ethereumjs/test/ipcprovider.js @@ -0,0 +1,58 @@ +var chai = require('chai'); +var assert = chai.assert; +var SandboxedModule = require('sandboxed-module'); + +SandboxedModule.registerBuiltInSourceTransformer('istanbul'); +var IpcProvider = SandboxedModule.require('../lib/web3/ipcprovider', { + requires: { + 'bignumber.js': require('bignumber.js'), + 'net': require('./helpers/FakeIpcRequest') + } +}); + +describe('lib/web3/ipcprovider', function () { + describe('send', function () { + it('should send basic request', function () { + var provider = new IpcProvider(); + var result = provider.send({id: 1, method: 'eth_test'}); + + assert.isObject(result); + }); + }); + + describe('sendAsync', function () { + it('should send basic async request', function (done) { + var provider = new IpcProvider(); + + provider.sendAsync({id: 1, method: 'eth_test'}, function (err, result) { + assert.isObject(result); + done(); + }); + }); + }); + + describe('isConnected', function () { + it('should return a boolean', function () { + var provider = new IpcProvider(); + + assert.isBoolean(provider.isConnected()); + }); + + it('should return false', function () { + var provider = new IpcProvider(); + + provider.connection.writable = false; + + assert.isFalse(provider.isConnected()); + }); + + it('should return true, when a net handle is set', function () { + var provider = new IpcProvider(); + + provider.connection.writable = true; + + assert.isTrue(provider.isConnected()); + }); + }); +}); + diff --git a/libjsqrc/ethereumjs/test/polling.js b/libjsqrc/ethereumjs/test/polling.js index 88cfee4cc..5c31e1390 100644 --- a/libjsqrc/ethereumjs/test/polling.js +++ b/libjsqrc/ethereumjs/test/polling.js @@ -63,8 +63,6 @@ var testPolling = function (tests) { var filter = web3[test.protocol].filter.apply(null, test.args); provider.injectBatchResults([test.secondResult]); filter.watch(function (err, result) { - console.log(err, result); - if (test.err) { // todo } else { diff --git a/libjsqrc/ethereumjs/test/qtsyncprovider.js b/libjsqrc/ethereumjs/test/qtsyncprovider.js deleted file mode 100644 index ce0064414..000000000 --- a/libjsqrc/ethereumjs/test/qtsyncprovider.js +++ /dev/null @@ -1,22 +0,0 @@ -var chai = require('chai'); -var assert = chai.assert; -var SandboxedModule = require('sandboxed-module'); - -SandboxedModule.registerBuiltInSourceTransformer('istanbul'); -var QtSyncProvider = SandboxedModule.require('../lib/web3/qtsync', { - globals: { - navigator: require('./helpers/FakeQtNavigator') - } -}); - -describe('/lib/web3/qtsyncprovider', function () { - describe('send', function () { - it('should send basic request', function () { - var provider = new QtSyncProvider(); - var result = provider.send({}); - - assert.equal(typeof result, 'object'); - }); - }); -}); - diff --git a/libjsqrc/ethereumjs/test/web3.eth.contract.js b/libjsqrc/ethereumjs/test/web3.eth.contract.js index b089f0243..fe8849f04 100644 --- a/libjsqrc/ethereumjs/test/web3.eth.contract.js +++ b/libjsqrc/ethereumjs/test/web3.eth.contract.js @@ -219,15 +219,27 @@ describe('web3.eth.contract', function() { ] }]; + var steps = 1; + provider.injectResult(address); provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_sendTransaction'); - assert.equal(payload.params[0].data, code + '0000000000000000000000000000000000000000000000000000000000000002'); - done(); + if(steps === 1) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_sendTransaction'); + assert.equal(payload.params[0].data, code + '0000000000000000000000000000000000000000000000000000000000000002'); + steps++; + + } else if(steps === 2) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_newBlockFilter'); + + done(); + } }); - var myCon = contract(description).new(2, {data: code}); + contract(description).new(2, {data: code}, function(e, myCon){ + + }); }); }); diff --git a/libjsqrc/ethereumjs/test/web3.eth.getTransaction.js b/libjsqrc/ethereumjs/test/web3.eth.getTransaction.js index b9ef034af..897bb1369 100644 --- a/libjsqrc/ethereumjs/test/web3.eth.getTransaction.js +++ b/libjsqrc/ethereumjs/test/web3.eth.getTransaction.js @@ -6,7 +6,6 @@ var testMethod = require('./helpers/test.method.js'); var method = 'getTransaction'; var txResult = { - "status": "mined", "hash":"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "nonce":"0x5", "blockHash": "0x6fd9e2a26ab", @@ -20,7 +19,6 @@ var txResult = { "input":"0x603880600c6000396000f30060" }; var formattedTxResult = { - "status": "mined", "hash":"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "nonce":5, "blockHash": "0x6fd9e2a26ab", diff --git a/libjsqrc/ethereumjs/test/web3.eth.getTransactionReceipt.js b/libjsqrc/ethereumjs/test/web3.eth.getTransactionReceipt.js new file mode 100644 index 000000000..f4398d9d9 --- /dev/null +++ b/libjsqrc/ethereumjs/test/web3.eth.getTransactionReceipt.js @@ -0,0 +1,70 @@ +var chai = require('chai'); +var web3 = require('../index'); +var BigNumber = require('bignumber.js'); +var testMethod = require('./helpers/test.method.js'); + +var method = 'getTransactionReceipt'; + +var txResult = { + "blockHash": "0x6fd9e2a26ab", + "blockNumber": "0x15df", + "transactionHash":"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", + "transactionIndex": "0x1", + "contractAddress":"0x407d73d8a49eeb85d32cf465507dd71d507100c1", + "cumulativeGasUsed":"0x7f110", + "gasUsed": "0x7f110", + "logs": [{ + transactionIndex: '0x3e8', + logIndex: '0x3e8', + blockNumber: '0x3e8', + transactionHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + blockHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + data: '0x7b2274657374223a2274657374227', + topics: ['0x68656c6c6f','0x6d79746f70696373'] + },{ + transactionIndex: null, + logIndex: null, + blockNumber: null, + transactionHash: null, + blockHash: null, + data: '0x7b2274657374223a2274657374227', + topics: ['0x68656c6c6f','0x6d79746f70696373'] + }] +}; +var formattedTxResult = { + "blockHash": "0x6fd9e2a26ab", + "blockNumber": 5599, + "transactionHash":"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", + "transactionIndex": 1, + "contractAddress":"0x407d73d8a49eeb85d32cf465507dd71d507100c1", + "cumulativeGasUsed": 520464, + "gasUsed": 520464, + "logs": [{ + transactionIndex: 1000, + logIndex: 1000, + blockNumber: 1000, + transactionHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + blockHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + data: '0x7b2274657374223a2274657374227', + topics: ['0x68656c6c6f','0x6d79746f70696373'] + },{ + transactionIndex: null, + logIndex: null, + blockNumber: null, + transactionHash: null, + blockHash: null, + data: '0x7b2274657374223a2274657374227', + topics: ['0x68656c6c6f','0x6d79746f70696373'] + }] +}; + +var tests = [{ + args: ['0x2dbab4c0612bf9caf4c195085547dc0612bf9caf4c1950855'], + formattedArgs: ['0x2dbab4c0612bf9caf4c195085547dc0612bf9caf4c1950855'], + result: txResult, + formattedResult: formattedTxResult, + call: 'eth_'+ method +}]; + +testMethod.runTests('eth', method, tests); + From 9917e7edd5c0d035923d503f37c71ccd3dc5e79f Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Jul 2015 17:51:28 +0200 Subject: [PATCH 107/113] Use actual addresses. --- test/libsolidity/SolidityWallet.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/test/libsolidity/SolidityWallet.cpp b/test/libsolidity/SolidityWallet.cpp index c829df783..707f49b1b 100644 --- a/test/libsolidity/SolidityWallet.cpp +++ b/test/libsolidity/SolidityWallet.cpp @@ -510,13 +510,20 @@ BOOST_AUTO_TEST_CASE(remove_owner) BOOST_AUTO_TEST_CASE(initial_owners) { - deployWallet(200, vector{5, 6, 7}, 2); - BOOST_CHECK(callContractFunction("m_numOwners()") == encodeArgs(u256(4))); + vector owners{ + u256("0x00000000000000000000000042c56279432962a17176998a4747d1b4d6ed4367"), + u256("0x000000000000000000000000d4d4669f5ba9f4c27d38ef02a358c339b5560c47"), + u256("0x000000000000000000000000e6716f9544a56c530d868e4bfbacb172315bdead"), + u256("0x000000000000000000000000775e18be7a50a0abb8a4e82b1bd697d79f31fe04"), + u256("0x000000000000000000000000f4dd5c3794f1fd0cdc0327a83aa472609c806e99"), + u256("0x0000000000000000000000004c9113886af165b2de069d6e99430647e94a9fff"), + u256("0x0000000000000000000000003fb1cd2cd96c6d5c0b5eb3322d807b34482481d4") + }; + deployWallet(0, owners, 4); + BOOST_CHECK(callContractFunction("m_numOwners()") == encodeArgs(u256(8))); BOOST_CHECK(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true)); - BOOST_CHECK(callContractFunction("isOwner(address)", u256(5)) == encodeArgs(true)); - BOOST_CHECK(callContractFunction("isOwner(address)", u256(6)) == encodeArgs(true)); - BOOST_CHECK(callContractFunction("isOwner(address)", u256(7)) == encodeArgs(true)); - BOOST_CHECK(callContractFunction("isOwner(address)", u256(8)) == encodeArgs(false)); + for (u256 const& owner: owners) + BOOST_CHECK(callContractFunction("isOwner(address)", owner) == encodeArgs(true)); } BOOST_AUTO_TEST_CASE(multisig_value_transfer) From 7d8bd8ec887712095b67968201133fb1fb5b6ce3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Jul 2015 17:52:19 +0200 Subject: [PATCH 108/113] Credits. Catch exceptions again. --- README.md | 19 +++++++++++++++++-- libethereum/BlockChain.cpp | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2bb57566c..5b56dbc11 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Join the chat at https://gitter.im/ethereum/cpp-ethereum](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/cpp-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -By Gav Wood et al, 2013, 2014, 2015. +By Gav Wood et al*, 2013, 2014, 2015. | Linux | OSX | Windows ----------|---------|-----|-------- @@ -12,7 +12,22 @@ evmjit | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=L [![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) -Ethereum is based on a design in an original whitepaper by Vitalik Buterin. This implementation is based on the formal specification of a refinement of that idea detailed in the 'yellow paper' by Gavin Wood. Contributors, builders and testers include Alex Leverington (Clang & Mac building, client multiplexing), Tim Hughes (MSVC compilation & Dagger testing), Caktux (ongoing CI), Christoph Jentzsch (tests), Christian Reissweiner (Solidity), Marek Kotewicz (external JS & JSON-RPC), Eric Lombrozo (MinGW32 cross-compilation), Marko Simovic (original CI), and several others. +Ethereum is based on a design in an original whitepaper by Vitalik Buterin. This implementation is based on the formal specification of a refinement of that idea detailed in the 'yellow paper' by Gavin Wood. Contributors, builders and testers include: + +- *arkpar* (**Arkadiy Paronyan**) Mix, PV61/BlockQueue +- *debris* (**Marek Kotewicz**) JSONRPC, web3.js +- *CJentzsch* (**Christoph Jentzsch**) tests, lots of tests +- *LefterisJP* (**Lefteris Karapetsas**) Solidity, libethash +- *chriseth* (**Christian Reitwiessner**) Solidity +- *subtly* (**Alex Leverington**) libp2p, rlpx +- *yann300* (**Yann Levreau**) Mix +- *LianaHus* (**Liana Husikyan**) Solidity +- *chfast* (**Paweł Bylica**) EVMJIT +- *cubedro* (**Marian Oancea**) web3.js +- *gluk250* (**Vlad Gluhovsky**) Whisper +- *programmerTim* (**Tim Hughes**) libethash-cl + +And let's not forget: Caktux (neth, ongoing CI), Eric Lombrozo (original MinGW32 cross-compilation), Marko Simovic (original CI). ### Building diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 320797ef3..d4fc1ce1b 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 0 +#define ETH_CATCH 1 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 From b1c04ba0fc8bb3fd3cbe79618c67f69e10703d9a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Jul 2015 18:24:40 +0200 Subject: [PATCH 109/113] Repot all the ethash stuff. Enable the previously disabled opencl mining paths. --- eth/main.cpp | 2 - ethminer/MinerAux.h | 41 +-- libethcore/Ethash.cpp | 425 +------------------------------- libethcore/Ethash.h | 3 + libethcore/EthashCPUMiner.cpp | 119 +++++++++ libethcore/EthashCPUMiner.h | 61 +++++ libethcore/EthashGPUMiner.cpp | 239 ++++++++++++++++++ libethcore/EthashGPUMiner.h | 82 ++++++ libethcore/EthashSealEngine.cpp | 72 ++++++ libethcore/EthashSealEngine.h | 56 +++++ libethereum/BlockChain.cpp | 6 +- 11 files changed, 650 insertions(+), 456 deletions(-) create mode 100644 libethcore/EthashCPUMiner.cpp create mode 100644 libethcore/EthashCPUMiner.h create mode 100644 libethcore/EthashGPUMiner.cpp create mode 100644 libethcore/EthashGPUMiner.h create mode 100644 libethcore/EthashSealEngine.cpp create mode 100644 libethcore/EthashSealEngine.h diff --git a/eth/main.cpp b/eth/main.cpp index 0b83c97b4..6128f30b6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1700,9 +1700,7 @@ int main(int argc, char** argv) c->setGasPricer(gasPricer); c->setForceMining(forceMining); // TODO: expose sealant interface. -#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); -#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 01083012f..447dfad0a 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #if ETH_ETHASHCL || !ETH_TRUE #include @@ -99,15 +101,10 @@ public: }; -#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} -#else - MinerCLI(OperationMode = OperationMode::None) {} -#endif bool interpretOption(int& i, int argc, char** argv) { -#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -246,7 +243,7 @@ public: string m; try { - BlockInfo bi; + Ethash::BlockHeader bi; m = boost::to_lower_copy(string(argv[++i])); h256 powHash(m); m = boost::to_lower_copy(string(argv[++i])); @@ -256,20 +253,20 @@ public: else seedHash = EthashAux::seedHash(stol(m)); m = boost::to_lower_copy(string(argv[++i])); - bi.difficulty = u256(m); + bi.setDifficulty(u256(m)); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.proof.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); + bi.setNonce(h64(m)); + auto r = EthashAux::eval(seedHash, powHash, bi.nonce()); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; - cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; + cout << " where " << boundary << " = 2^256 / " << bi.difficulty() << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce() << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; exit(0); } catch (...) @@ -294,29 +291,22 @@ public: else return false; return true; -#else - (void)i; - (void)argc; - (void)argv; - return false; -#endif } void execute() { -#if ETH_USING_ETHASH if (m_shouldListDevices) { - Ethash::GPUMiner::listDevices(); + EthashGPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - Ethash::CPUMiner::setNumInstances(m_miningThreads); + EthashCPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!Ethash::GPUMiner::configureGPU( + if (!EthashGPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -327,7 +317,7 @@ public: m_currentBlock )) exit(1); - Ethash::GPUMiner::setNumInstances(m_miningThreads); + EthashGPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -339,12 +329,10 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); -#endif } static void streamHelp(ostream& _out) { -#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -381,9 +369,6 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; -#else - (void)_out; -#endif } enum class MinerType diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 09c6cbe19..f1149966a 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -38,19 +37,15 @@ #include #include #include -#if ETH_ETHASHCL || !ETH_TRUE -#include -#endif -#if ETH_CPUID || !ETH_TRUE -#define HAVE_STDINT_H -#include -#endif #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" #include "Farm.h" #include "Miner.h" #include "Params.h" +#include "EthashSealEngine.h" +#include "EthashCPUMiner.h" +#include "EthashGPUMiner.h" using namespace std; using namespace std::chrono; @@ -184,135 +179,6 @@ StringHashMap Ethash::BlockHeaderRaw::jsInfo() const - - - - -class EthashCPUMiner: public GenericMiner, Worker -{ -public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} - - 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, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - -protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } - - void pause() override { stopWorking(); } - -private: - void workLoop() override; - static unsigned s_numInstances; -}; - -#if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker -{ - friend class dev::eth::EthashCLHook; - -public: - EthashGPUMiner(ConstructionInfo const& _ci); - ~EthashGPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } - -protected: - void kickOff() override; - void pause() override; - -private: - void workLoop() override; - bool report(uint64_t _nonce); - - using GenericMiner::accumulateHashes; - - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; - - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; -}; -#endif - -struct EthashSealEngine: public SealEngineBase -{ - friend class Ethash; - -public: - EthashSealEngine() - { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; -#if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; -#endif - m_farm.setSealers(sealers); - } - - strings sealers() const override - { - return { - "cpu" -#if ETH_ETHASHCL - , "opencl" -#endif - }; - } - void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void cancelGeneration() override { m_farm.stop(); } - void generateSeal(BlockInfo const& _bi) override - { - m_sealing = Ethash::BlockHeader(_bi); - m_farm.setWork(m_sealing); - m_farm.start(m_sealer); - m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number()); - } - void onSealGenerated(std::function const& _f) override - { - m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) - { - cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - m_sealing.m_mixHash = sol.mixHash; - m_sealing.m_nonce = sol.nonce; - RLPStream ret; - m_sealing.streamRLP(ret); - _f(ret.out()); - return true; - }); - } - -private: - bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer = "cpu"; - Ethash::BlockHeader m_sealing; -}; - void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) { if (EthashSealEngine* e = dynamic_cast(_engine)) @@ -358,290 +224,5 @@ void Ethash::ensurePrecomputed(unsigned _number) EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned EthashCPUMiner::s_numInstances = 0; - -void EthashCPUMiner::workLoop() -{ - auto tid = std::this_thread::get_id(); - static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); - - uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng); - ethash_return_value ethashReturn; - - WorkPackage w = work(); - - EthashAux::FullType dag; - while (!shouldStop() && !dag) - { - while (!shouldStop() && EthashAux::computeFull(w.seedHash, true) != 100) - this_thread::sleep_for(chrono::milliseconds(500)); - dag = EthashAux::full(w.seedHash, false); - } - - h256 boundary = w.boundary; - unsigned hashCount = 1; - for (; !shouldStop(); tryNonce++, hashCount++) - { - ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); - h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) - break; - if (!(hashCount % 100)) - accumulateHashes(100); - } -} - -static string jsonEncode(map const& _m) -{ - string ret = "{"; - - for (auto const& i: _m) - { - string k = boost::replace_all_copy(boost::replace_all_copy(i.first, "\\", "\\\\"), "'", "\\'"); - string v = boost::replace_all_copy(boost::replace_all_copy(i.second, "\\", "\\\\"), "'", "\\'"); - if (ret.size() > 1) - ret += ", "; - ret += "\"" + k + "\":\"" + v + "\""; - } - - return ret + "}"; -} - -std::string EthashCPUMiner::platformInfo() -{ - string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; -#if ETH_CPUID || !ETH_TRUE - if (!cpuid_present()) - return baseline; - struct cpu_raw_data_t raw; - struct cpu_id_t data; - if (cpuid_get_raw_data(&raw) < 0) - return baseline; - if (cpu_identify(&raw, &data) < 0) - return baseline; - map m; - m["vendor"] = data.vendor_str; - m["codename"] = data.cpu_codename; - m["brand"] = data.brand_str; - m["L1 cache"] = toString(data.l1_data_cache); - m["L2 cache"] = toString(data.l2_cache); - m["L3 cache"] = toString(data.l3_cache); - m["cores"] = toString(data.num_cores); - m["threads"] = toString(data.num_logical_cpus); - m["clocknominal"] = toString(cpu_clock_by_os()); - m["clocktested"] = toString(cpu_clock_measure(200, 0)); - /* - printf(" MMX : %s\n", data.flags[CPU_FEATURE_MMX] ? "present" : "absent"); - printf(" MMX-extended: %s\n", data.flags[CPU_FEATURE_MMXEXT] ? "present" : "absent"); - printf(" SSE : %s\n", data.flags[CPU_FEATURE_SSE] ? "present" : "absent"); - printf(" SSE2 : %s\n", data.flags[CPU_FEATURE_SSE2] ? "present" : "absent"); - printf(" 3DNow! : %s\n", data.flags[CPU_FEATURE_3DNOW] ? "present" : "absent"); - */ - return jsonEncode(m); -#else - return baseline; -#endif -} - -#if ETH_ETHASHCL || !ETH_TRUE - -class EthashCLHook: public ethash_cl_miner::search_hook -{ -public: - EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {} - EthashCLHook(EthashCLHook const&) = delete; - - void abort() - { - { - UniqueGuard l(x_all); - if (m_aborted) - return; -// cdebug << "Attempting to abort"; - - m_abort = true; - } - // m_abort is true so now searched()/found() will return true to abort the search. - // we hang around on this thread waiting for them to point out that they have aborted since - // otherwise we may end up deleting this object prior to searched()/found() being called. - m_aborted.wait(true); -// for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) -// std::this_thread::sleep_for(chrono::milliseconds(30)); -// if (!m_aborted) -// cwarn << "Couldn't abort. Abandoning OpenCL process."; - } - - void reset() - { - UniqueGuard l(x_all); - m_aborted = m_abort = false; - } - -protected: - virtual bool found(uint64_t const* _nonces, uint32_t _count) override - { -// dev::operator <<(std::cerr << "Found nonces: ", vector(_nonces, _nonces + _count)) << std::endl; - for (uint32_t i = 0; i < _count; ++i) - if (m_owner->report(_nonces[i])) - return (m_aborted = true); - return m_owner->shouldStop(); - } - - virtual bool searched(uint64_t _startNonce, uint32_t _count) override - { - UniqueGuard l(x_all); -// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; - m_owner->accumulateHashes(_count); - m_last = _startNonce + _count; - if (m_abort || m_owner->shouldStop()) - return (m_aborted = true); - return false; - } - -private: - Mutex x_all; - uint64_t m_last; - bool m_abort = false; - Notified m_aborted = {true}; - EthashGPUMiner* m_owner = nullptr; -}; - -unsigned EthashGPUMiner::s_platformId = 0; -unsigned EthashGPUMiner::s_deviceId = 0; -unsigned EthashGPUMiner::s_numInstances = 0; - -EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): - GenericMiner(_ci), - Worker("gpuminer" + toString(index())), - m_hook(new EthashCLHook(this)) -{ -} - -EthashGPUMiner::~EthashGPUMiner() -{ - pause(); - delete m_miner; - delete m_hook; -} - -bool EthashGPUMiner::report(uint64_t _nonce) -{ - Nonce n = (Nonce)(u64)_nonce; - EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n); - if (r.value < work().boundary) - return submitProof(Solution{n, r.mixHash}); - return false; -} - -void EthashGPUMiner::kickOff() -{ - m_hook->reset(); - startWorking(); -} - -void EthashGPUMiner::workLoop() -{ - // take local copy of work since it may end up being overwritten by kickOff/pause. - try { - WorkPackage w = work(); - cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash; - if (!m_miner || m_minerSeed != w.seedHash) - { - cnote << "Initialising miner..."; - m_minerSeed = w.seedHash; - - delete m_miner; - m_miner = new ethash_cl_miner; - - unsigned device = instances() > 1 ? index() : s_deviceId; - - EthashAux::FullType dag; - while (true) - { - if ((dag = EthashAux::full(w.seedHash, true))) - break; - if (shouldStop()) - { - delete m_miner; - m_miner = nullptr; - return; - } - cnote << "Awaiting DAG"; - this_thread::sleep_for(chrono::milliseconds(500)); - } - bytesConstRef dagData = dag->data(); - m_miner->init(dagData.data(), dagData.size(), s_platformId, device); - } - - uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); - m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); - } - catch (cl::Error const& _e) - { - delete m_miner; - m_miner = nullptr; - cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")"; - } -} - -void EthashGPUMiner::pause() -{ - m_hook->abort(); - stopWorking(); -} - -std::string EthashGPUMiner::platformInfo() -{ - return ethash_cl_miner::platform_info(s_platformId, s_deviceId); -} - -unsigned EthashGPUMiner::getNumDevices() -{ - return ethash_cl_miner::getNumDevices(s_platformId); -} - -void EthashGPUMiner::listDevices() -{ - return ethash_cl_miner::listDevices(); -} - -bool EthashGPUMiner::configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock -) -{ - s_platformId = _platformId; - s_deviceId = _deviceId; - - if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128) - { - cout << "Given localWorkSize of " << toString(_localWorkSize) << "is invalid. Must be either 32,64, or 128" << endl; - return false; - } - - if (!ethash_cl_miner::configureGPU( - _platformId, - _localWorkSize, - _globalWorkSizeMultiplier * _localWorkSize, - _msPerBatch, - _allowCPU, - _extraGPUMemory, - _currentBlock) - ) - { - cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl; - return false; - } - return true; -} - -#endif - } } diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 576621bd4..0ea80f5e1 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -74,6 +74,9 @@ public: Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + void setNonce(Nonce const& _n) { m_nonce = _n; noteDirty(); } + void setMixHash(h256 const& _n) { m_mixHash = _n; noteDirty(); } + StringHashMap jsInfo() const; protected: diff --git a/libethcore/EthashCPUMiner.cpp b/libethcore/EthashCPUMiner.cpp new file mode 100644 index 000000000..2e8a05018 --- /dev/null +++ b/libethcore/EthashCPUMiner.cpp @@ -0,0 +1,119 @@ +/* + 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 EthashCPUMiner.cpp + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#include "EthashCPUMiner.h" +#include +#include +#include +#if ETH_CPUID || !ETH_TRUE +#define HAVE_STDINT_H +#include +#endif +using namespace std; +using namespace dev; +using namespace eth; + +unsigned EthashCPUMiner::s_numInstances = 0; + +static string jsonEncode(map const& _m) +{ + string ret = "{"; + + for (auto const& i: _m) + { + string k = boost::replace_all_copy(boost::replace_all_copy(i.first, "\\", "\\\\"), "'", "\\'"); + string v = boost::replace_all_copy(boost::replace_all_copy(i.second, "\\", "\\\\"), "'", "\\'"); + if (ret.size() > 1) + ret += ", "; + ret += "\"" + k + "\":\"" + v + "\""; + } + + return ret + "}"; +} + +void EthashCPUMiner::workLoop() +{ + auto tid = std::this_thread::get_id(); + static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); + + uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng); + ethash_return_value ethashReturn; + + WorkPackage w = work(); + + EthashAux::FullType dag; + while (!shouldStop() && !dag) + { + while (!shouldStop() && EthashAux::computeFull(w.seedHash, true) != 100) + this_thread::sleep_for(chrono::milliseconds(500)); + dag = EthashAux::full(w.seedHash, false); + } + + h256 boundary = w.boundary; + unsigned hashCount = 1; + for (; !shouldStop(); tryNonce++, hashCount++) + { + ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); + h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + break; + if (!(hashCount % 100)) + accumulateHashes(100); + } +} + +std::string EthashCPUMiner::platformInfo() +{ + string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; +#if ETH_CPUID || !ETH_TRUE + if (!cpuid_present()) + return baseline; + struct cpu_raw_data_t raw; + struct cpu_id_t data; + if (cpuid_get_raw_data(&raw) < 0) + return baseline; + if (cpu_identify(&raw, &data) < 0) + return baseline; + map m; + m["vendor"] = data.vendor_str; + m["codename"] = data.cpu_codename; + m["brand"] = data.brand_str; + m["L1 cache"] = toString(data.l1_data_cache); + m["L2 cache"] = toString(data.l2_cache); + m["L3 cache"] = toString(data.l3_cache); + m["cores"] = toString(data.num_cores); + m["threads"] = toString(data.num_logical_cpus); + m["clocknominal"] = toString(cpu_clock_by_os()); + m["clocktested"] = toString(cpu_clock_measure(200, 0)); + /* + printf(" MMX : %s\n", data.flags[CPU_FEATURE_MMX] ? "present" : "absent"); + printf(" MMX-extended: %s\n", data.flags[CPU_FEATURE_MMXEXT] ? "present" : "absent"); + printf(" SSE : %s\n", data.flags[CPU_FEATURE_SSE] ? "present" : "absent"); + printf(" SSE2 : %s\n", data.flags[CPU_FEATURE_SSE2] ? "present" : "absent"); + printf(" 3DNow! : %s\n", data.flags[CPU_FEATURE_3DNOW] ? "present" : "absent"); + */ + return jsonEncode(m); +#else + return baseline; +#endif +} diff --git a/libethcore/EthashCPUMiner.h b/libethcore/EthashCPUMiner.h new file mode 100644 index 000000000..ff3c58df1 --- /dev/null +++ b/libethcore/EthashCPUMiner.h @@ -0,0 +1,61 @@ +/* + 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 EthashCPUMiner.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include "libdevcore/Worker.h" +#include "EthashAux.h" +#include "Miner.h" + +namespace dev +{ +namespace eth +{ + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + 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, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } + +protected: + void kickOff() override + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +} +} diff --git a/libethcore/EthashGPUMiner.cpp b/libethcore/EthashGPUMiner.cpp new file mode 100644 index 000000000..58e46c263 --- /dev/null +++ b/libethcore/EthashGPUMiner.cpp @@ -0,0 +1,239 @@ +/* + 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 EthashGPUMiner.cpp + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#if ETH_ETHASHCL || !ETH_TRUE + +#include "EthashGPUMiner.h" +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; + +namespace dev +{ +namespace eth +{ + +class EthashCLHook: public ethash_cl_miner::search_hook +{ +public: + EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {} + EthashCLHook(EthashCLHook const&) = delete; + + void abort() + { + { + UniqueGuard l(x_all); + if (m_aborted) + return; +// cdebug << "Attempting to abort"; + + m_abort = true; + } + // m_abort is true so now searched()/found() will return true to abort the search. + // we hang around on this thread waiting for them to point out that they have aborted since + // otherwise we may end up deleting this object prior to searched()/found() being called. + m_aborted.wait(true); +// for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) +// std::this_thread::sleep_for(chrono::milliseconds(30)); +// if (!m_aborted) +// cwarn << "Couldn't abort. Abandoning OpenCL process."; + } + + void reset() + { + UniqueGuard l(x_all); + m_aborted = m_abort = false; + } + +protected: + virtual bool found(uint64_t const* _nonces, uint32_t _count) override + { +// dev::operator <<(std::cerr << "Found nonces: ", vector(_nonces, _nonces + _count)) << std::endl; + for (uint32_t i = 0; i < _count; ++i) + if (m_owner->report(_nonces[i])) + return (m_aborted = true); + return m_owner->shouldStop(); + } + + virtual bool searched(uint64_t _startNonce, uint32_t _count) override + { + UniqueGuard l(x_all); +// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; + m_owner->accumulateHashes(_count); + m_last = _startNonce + _count; + if (m_abort || m_owner->shouldStop()) + return (m_aborted = true); + return false; + } + +private: + Mutex x_all; + uint64_t m_last; + bool m_abort = false; + Notified m_aborted = {true}; + EthashGPUMiner* m_owner = nullptr; +}; + +} +} + +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; + +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): + GenericMiner(_ci), + Worker("gpuminer" + toString(index())), + m_hook(new EthashCLHook(this)) +{ +} + +EthashGPUMiner::~EthashGPUMiner() +{ + pause(); + delete m_miner; + delete m_hook; +} + +bool EthashGPUMiner::report(uint64_t _nonce) +{ + Nonce n = (Nonce)(u64)_nonce; + EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n); + if (r.value < work().boundary) + return submitProof(Solution{n, r.mixHash}); + return false; +} + +void EthashGPUMiner::kickOff() +{ + m_hook->reset(); + startWorking(); +} + +void EthashGPUMiner::workLoop() +{ + // take local copy of work since it may end up being overwritten by kickOff/pause. + try { + WorkPackage w = work(); + cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash; + if (!m_miner || m_minerSeed != w.seedHash) + { + cnote << "Initialising miner..."; + m_minerSeed = w.seedHash; + + delete m_miner; + m_miner = new ethash_cl_miner; + + unsigned device = instances() > 1 ? index() : s_deviceId; + + EthashAux::FullType dag; + while (true) + { + if ((dag = EthashAux::full(w.seedHash, true))) + break; + if (shouldStop()) + { + delete m_miner; + m_miner = nullptr; + return; + } + cnote << "Awaiting DAG"; + this_thread::sleep_for(chrono::milliseconds(500)); + } + bytesConstRef dagData = dag->data(); + m_miner->init(dagData.data(), dagData.size(), s_platformId, device); + } + + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); + m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); + } + catch (cl::Error const& _e) + { + delete m_miner; + m_miner = nullptr; + cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")"; + } +} + +void EthashGPUMiner::pause() +{ + m_hook->abort(); + stopWorking(); +} + +std::string EthashGPUMiner::platformInfo() +{ + return ethash_cl_miner::platform_info(s_platformId, s_deviceId); +} + +unsigned EthashGPUMiner::getNumDevices() +{ + return ethash_cl_miner::getNumDevices(s_platformId); +} + +void EthashGPUMiner::listDevices() +{ + return ethash_cl_miner::listDevices(); +} + +bool EthashGPUMiner::configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + uint64_t _currentBlock +) +{ + s_platformId = _platformId; + s_deviceId = _deviceId; + + if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128) + { + cout << "Given localWorkSize of " << toString(_localWorkSize) << "is invalid. Must be either 32,64, or 128" << endl; + return false; + } + + if (!ethash_cl_miner::configureGPU( + _platformId, + _localWorkSize, + _globalWorkSizeMultiplier * _localWorkSize, + _msPerBatch, + _allowCPU, + _extraGPUMemory, + _currentBlock) + ) + { + cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl; + return false; + } + return true; +} + +#endif diff --git a/libethcore/EthashGPUMiner.h b/libethcore/EthashGPUMiner.h new file mode 100644 index 000000000..f4b0fcc0d --- /dev/null +++ b/libethcore/EthashGPUMiner.h @@ -0,0 +1,82 @@ +/* + 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 EthashGPUMiner.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once +#if ETH_ETHASHCL || !ETH_TRUE + +#include "libdevcore/Worker.h" +#include "EthashAux.h" +#include "Miner.h" + +namespace dev +{ +namespace eth +{ + +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + uint64_t _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using GenericMiner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; + +} +} + +#endif diff --git a/libethcore/EthashSealEngine.cpp b/libethcore/EthashSealEngine.cpp new file mode 100644 index 000000000..290ec427b --- /dev/null +++ b/libethcore/EthashSealEngine.cpp @@ -0,0 +1,72 @@ +/* + 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 EthashSealEngine.cpp + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#include "EthashSealEngine.h" +#include "EthashCPUMiner.h" +#include "EthashGPUMiner.h" +using namespace std; +using namespace dev; +using namespace eth; + +EthashSealEngine::EthashSealEngine() +{ + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); +} + +strings EthashSealEngine::sealers() const +{ + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; +} + +void EthashSealEngine::generateSeal(BlockInfo const& _bi) +{ + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); + m_farm.start(m_sealer); + m_farm.setWork(m_sealing); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number()); +} + +void EthashSealEngine::onSealGenerated(std::function const& _f) +{ + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) + { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); + return true; + }); +} diff --git a/libethcore/EthashSealEngine.h b/libethcore/EthashSealEngine.h new file mode 100644 index 000000000..16e9b5788 --- /dev/null +++ b/libethcore/EthashSealEngine.h @@ -0,0 +1,56 @@ +/* + 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 EthashSealEngine.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include "Sealer.h" +#include "Ethash.h" +#include "EthashAux.h" + +namespace dev +{ +namespace eth +{ + +class EthashSealEngine: public SealEngineBase +{ + friend class Ethash; + +public: + EthashSealEngine(); + + strings sealers() const override; + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void cancelGeneration() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override; + void onSealGenerated(std::function const& _f) override; + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index d4fc1ce1b..5dfd66cee 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -578,15 +578,13 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif -#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutProof).abridged(), - _block.info.proof.nonce.abridged(), + _block.info.hashWithout().abridged(), + "",//_block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash().abridged() ); -#endif // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; From a8b8ce540feea3c1d4909548ba7afdb31b9e68d0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Jul 2015 18:44:06 +0200 Subject: [PATCH 110/113] Windows fix. --- test/libsolidity/SolidityWallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/libsolidity/SolidityWallet.cpp b/test/libsolidity/SolidityWallet.cpp index 707f49b1b..b5f0f7249 100644 --- a/test/libsolidity/SolidityWallet.cpp +++ b/test/libsolidity/SolidityWallet.cpp @@ -523,7 +523,9 @@ BOOST_AUTO_TEST_CASE(initial_owners) BOOST_CHECK(callContractFunction("m_numOwners()") == encodeArgs(u256(8))); BOOST_CHECK(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true)); for (u256 const& owner: owners) + { BOOST_CHECK(callContractFunction("isOwner(address)", owner) == encodeArgs(true)); + } } BOOST_AUTO_TEST_CASE(multisig_value_transfer) From 631e701fdf0b7ebdb5b50083625c54364b4e075e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Jul 2015 19:18:51 +0200 Subject: [PATCH 111/113] Fix dejavu week 1, issue 1. Reenable bits of ethash. --- libdevcore/CommonIO.cpp | 2 ++ libethereum/BlockChain.cpp | 6 ++---- libethereum/Client.h | 1 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 18 +++++------------- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index 055b645ed..067d75559 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -111,11 +111,13 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDe // create directory if not existent fs::path p(_file); fs::create_directories(p.parent_path()); + fs::permissions(p.parent_path(), fs::owner_all); ofstream s(_file, ios::trunc | ios::binary); s.write(reinterpret_cast(_data.data()), _data.size()); if (!s) BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file)); + fs::permissions(_file, fs::owner_read|fs::owner_write); } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 5dfd66cee..61c3ecf0c 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -669,14 +669,12 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; -#if ETH_USING_ETHASH StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutProof).abridged(), - _block.info.proof.nonce.abridged(), + _block.info.hashWithout().abridged(), + "",//_block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash().abridged() ); -#endif } else { diff --git a/libethereum/Client.h b/libethereum/Client.h index 896444176..8ea28ec1e 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -380,6 +380,7 @@ public: /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. + /// @returns Tuple of target boundary, hash without seal, seed hash. virtual std::tuple getEthashWork() override; /** @brief Submit the proof for the proof-of-work. diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index df2006cc5..4363b2466 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -748,12 +748,10 @@ Json::Value WebThreeStubServerBase::eth_getLogsEx(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); -#if ETH_USING_ETHASH - auto r = client()->getWork(); - ret.append(toJS(r.headerHash)); - ret.append(toJS(r.seedHash)); - ret.append(toJS(r.boundary)); -#endif + auto r = client()->getEthashWork(); + ret.append(toJS(get<0>(r))); + ret.append(toJS(get<1>(r))); + ret.append(toJS(get<2>(r))); return ret; } @@ -761,13 +759,7 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { -#if ETH_USING_ETHASH - return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); -#else - (void)_nonce; - (void)_mixHash; - return false; -#endif + return client()->submitEthashWork(jsToFixed<32>(_mixHash), jsToFixed(_nonce)); } catch (...) { From 51f887aac5e7906f18dfe1aa74cd08be00ddd4a2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Jul 2015 19:38:40 +0200 Subject: [PATCH 112/113] Make sure all directories are not readable by baddies (dejavu wk1#0). Closes #2509. Remove neth :(. Who knows, perhaps not forever... --- CMakeLists.txt | 17 +- alethzero/NatspecHandler.cpp | 5 +- libdevcore/TransientDirectory.cpp | 8 +- libdevcrypto/SecretStore.cpp | 2 + libethereum/BlockChain.cpp | 5 +- libethereum/State.cpp | 1 + libethereum/Utility.cpp | 6 +- libweb3jsonrpc/WebThreeStubServer.cpp | 4 +- libwhisper/WhisperDB.cpp | 5 +- neth/CMakeLists.txt | 26 - neth/main.cpp | 1497 ------------------------- 11 files changed, 25 insertions(+), 1551 deletions(-) delete mode 100644 neth/CMakeLists.txt delete mode 100644 neth/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3330977aa..7fb6b3b94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,6 @@ option(ETHKEY "Build the CLI key manager component" ON) option(SOLIDITY "Build the Solidity language components" ON) option(SERPENT "Build the Serpent language components" ON) option(TOOLS "Build the tools components" ON) -option(NCURSES "Build the NCurses components" OFF) option(GUI "Build GUI components (AlethZero, Mix)" ON) option(TESTS "Build the tests." ON) option(NOBOOST "No use of boost macros in test functions" OFF) @@ -209,7 +208,6 @@ eth_format_option(ETHKEY) eth_format_option(ETHASHCL) eth_format_option(JSCONSOLE) eth_format_option_on_decent_platform(SERPENT) -eth_format_option_on_decent_platform(NCURSES) if (JSCONSOLE) set(JSONRPC ON) @@ -227,7 +225,6 @@ if (BUNDLE STREQUAL "minimal") set(SOLIDITY OFF) set(USENPM OFF) set(GUI OFF) - set(NCURSES OFF) set(TOOLS ON) set(TESTS OFF) elseif (BUNDLE STREQUAL "full") @@ -235,7 +232,6 @@ elseif (BUNDLE STREQUAL "full") set(SOLIDITY ON) set(USENPM ON) set(GUI ON) -# set(NCURSES ${DECENT_PLATFORM}) set(TOOLS ON) set(TESTS ON) set(FATDB ON) @@ -244,7 +240,6 @@ elseif (BUNDLE STREQUAL "cli") set(SOLIDITY ON) set(USENPM ON) set(GUI OFF) -# set(NCURSES ${DECENT_PLATFORM}) set(TOOLS ON) set(TESTS ON) set(FATDB ON) @@ -253,7 +248,6 @@ elseif (BUNDLE STREQUAL "core") set(SOLIDITY ON) set(USENPM OFF) set(GUI ON) - set(NCURSES OFF) set(TOOLS ON) set(TESTS OFF) set(FATDB ON) @@ -262,7 +256,6 @@ elseif (BUNDLE STREQUAL "tests") set(SOLIDITY ON) set(USENPM OFF) set(GUI OFF) - set(NCURSES OFF) set(TOOLS OFF) set(TESTS ON) set(FATDB ON) @@ -271,7 +264,6 @@ elseif (BUNDLE STREQUAL "user") set(SOLIDITY OFF) set(USENPM OFF) set(GUI ON) -# set(NCURSES ${DECENT_PLATFORM}) set(TOOLS ON) set(TESTS OFF) elseif (BUNDLE STREQUAL "wallet") @@ -279,7 +271,6 @@ elseif (BUNDLE STREQUAL "wallet") set(SOLIDITY OFF) set(USENPM OFF) set(GUI OFF) - set(NCURSES OFF) set(TOOLS OFF) set(TESTS OFF) set(ETHKEY ON) @@ -290,7 +281,6 @@ elseif (BUNDLE STREQUAL "miner") set(SOLIDITY OFF) set(USENPM OFF) set(GUI OFF) - set(NCURSES OFF) set(TOOLS OFF) set(TESTS OFF) set(ETHKEY OFF) @@ -338,7 +328,6 @@ message("-- TOOLS Build basic tools ${TOOLS}") message("-- SOLIDITY Build Solidity language components ${SOLIDITY}") message("-- SERPENT Build Serpent language components ${SERPENT}") message("-- GUI Build GUI components ${GUI}") -message("-- NCURSES Build NCurses components ${NCURSES}") message("-- TESTS Build tests ${TESTS}") message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}") message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}") @@ -373,7 +362,7 @@ if (EVMJIT) add_subdirectory(evmjit) endif() -if (TOOLS OR GUI OR SOLIDITY OR NCURSES OR TESTS) +if (TOOLS OR GUI OR SOLIDITY OR TESTS) set(GENERAL 1) else () set(GENERAL 0) @@ -469,10 +458,6 @@ if (TOOLS) endif() -#if (NCURSES) -# add_subdirectory(neth) -#endif () - if (GUI) add_subdirectory(libnatspec) diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index d00abc44f..6ed9f2b10 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -29,15 +29,16 @@ #include #include #include - using namespace dev; using namespace dev::eth; using namespace std; +namespace fs = boost::filesystem; NatspecHandler::NatspecHandler() { string path = Defaults::dbPath(); - boost::filesystem::create_directories(path); + fs::create_directories(path); + fs::permissions(path, fs::owner_all); ldb::Options o; o.create_if_missing = true; ldb::DB::Open(o, path + "/natspec", &m_db); diff --git a/libdevcore/TransientDirectory.cpp b/libdevcore/TransientDirectory.cpp index 8b7aa4467..31a826c24 100644 --- a/libdevcore/TransientDirectory.cpp +++ b/libdevcore/TransientDirectory.cpp @@ -27,6 +27,7 @@ #include "Log.h" using namespace std; using namespace dev; +namespace fs = boost::filesystem; TransientDirectory::TransientDirectory(): TransientDirectory((boost::filesystem::temp_directory_path() / "eth_transient" / toString(FixedHash<4>::random())).string()) @@ -39,13 +40,14 @@ TransientDirectory::TransientDirectory(std::string const& _path): if (boost::filesystem::exists(m_path)) BOOST_THROW_EXCEPTION(FileError()); - boost::filesystem::create_directories(m_path); + fs::create_directories(m_path); + fs::permissions(m_path, fs::owner_all); } TransientDirectory::~TransientDirectory() { boost::system::error_code ec; - boost::filesystem::remove_all(m_path, ec); + fs::remove_all(m_path, ec); if (!ec) return; @@ -56,7 +58,7 @@ TransientDirectory::~TransientDirectory() this_thread::sleep_for(chrono::milliseconds(10)); ec.clear(); - boost::filesystem::remove_all(m_path, ec); + fs::remove_all(m_path, ec); if (!ec) cwarn << "Failed to delete directory '" << m_path << "': " << ec.message(); } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index a7a16a1b8..55c944e8e 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -137,6 +137,7 @@ void SecretStore::save(string const& _keysPath) { fs::path p(_keysPath); fs::create_directories(p); + fs::permissions(p, fs::owner_all); for (auto& k: m_keys) { string uuid = toUUID(k.first); @@ -158,6 +159,7 @@ void SecretStore::load(string const& _keysPath) { fs::path p(_keysPath); fs::create_directories(p); + fs::permissions(p, fs::owner_all); for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) if (fs::is_regular_file(it->path())) readKey(it->path().string(), true); diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 61c3ecf0c..a992c5851 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -42,11 +42,11 @@ #include "State.h" #include "Utility.h" #include "Defaults.h" - using namespace std; using namespace dev; using namespace dev::eth; namespace js = json_spirit; +namespace fs = boost::filesystem; #define ETH_CATCH 1 #define ETH_TIMED_IMPORTS 1 @@ -156,7 +156,8 @@ unsigned BlockChain::open(std::string const& _path, WithExisting _we) string chainPath = path + "/" + toHex(m_genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(c_databaseVersion); - boost::filesystem::create_directories(extrasPath); + fs::create_directories(extrasPath); + fs::permissions(extrasPath, fs::owner_all); bytes status = contents(extrasPath + "/minor"); unsigned lastMinor = c_minorProtocolVersion; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 64daaf5f8..95bb0febb 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -67,6 +67,7 @@ OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); + fs::permissions(path, fs::owner_all); ldb::Options o; o.max_open_files = 256; diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index 1b97f82e7..f34f66463 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -113,12 +113,14 @@ void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesi // write status if (!fs::exists(chainPath + "/blocks")) { - boost::filesystem::create_directories(chainPath); + fs::create_directories(chainPath); + fs::permissions(chainPath, fs::owner_all); fs::rename(path + "/blocks", chainPath + "/blocks"); if (!fs::exists(extrasPath + "/extras")) { - boost::filesystem::create_directories(extrasPath); + fs::create_directories(extrasPath); + fs::permissions(extrasPath, fs::owner_all); fs::rename(path + "/details", extrasPath + "/extras"); fs::rename(path + "/state", extrasPath + "/state"); writeFile(extrasPath + "/minor", rlp(minorProtocolVersion)); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index bf49d3322..0a7277e06 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -34,6 +34,7 @@ using namespace std; using namespace dev; using namespace dev::eth; +namespace fs = boost::filesystem; bool isHex(std::string const& _s) { @@ -56,7 +57,8 @@ WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, m_gp(_gp) { auto path = getDataDir() + "/.web3"; - boost::filesystem::create_directories(path); + fs::create_directories(path); + fs::permissions(path, fs::owner_all); ldb::Options o; o.create_if_missing = true; ldb::DB::Open(o, path, &m_db); diff --git a/libwhisper/WhisperDB.cpp b/libwhisper/WhisperDB.cpp index 7104723d7..9f7cebbeb 100644 --- a/libwhisper/WhisperDB.cpp +++ b/libwhisper/WhisperDB.cpp @@ -22,16 +22,17 @@ #include "WhisperDB.h" #include #include - using namespace std; using namespace dev; using namespace dev::shh; +namespace fs = boost::filesystem; WhisperDB::WhisperDB() { m_readOptions.verify_checksums = true; string path = dev::getDataDir("shh"); - boost::filesystem::create_directories(path); + fs::create_directories(path); + fs::permissions(path, fs::owner_all); leveldb::Options op; op.create_if_missing = true; op.max_open_files = 256; diff --git a/neth/CMakeLists.txt b/neth/CMakeLists.txt deleted file mode 100644 index 68de36368..000000000 --- a/neth/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_policy(SET CMP0015 NEW) - -aux_source_directory(. SRC_LIST) - -include_directories(BEFORE ..) -include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -include_directories(${DB_INCLUDE_DIRS}) -include_directories(${Boost_INCLUDE_DIRS}) - -set(EXECUTABLE neth) - -add_executable(${EXECUTABLE} ${SRC_LIST}) - -add_dependencies(${EXECUTABLE} BuildInfo.h) - -if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) -endif() - -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} ncurses) -target_link_libraries(${EXECUTABLE} form) - -install( TARGETS ${EXECUTABLE} DESTINATION bin ) - diff --git a/neth/main.cpp b/neth/main.cpp deleted file mode 100644 index c3dc65715..000000000 --- a/neth/main.cpp +++ /dev/null @@ -1,1497 +0,0 @@ -/* - 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 main.cpp - * @author Gav Wood - * @date 2014 - * Ethereum client. - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#if ETH_JSONRPC || !ETH_TRUE -#include -#include -#include -#endif -#include "BuildInfo.h" - -#undef KEY_EVENT // from windows.h -#include -#undef OK -#include -#undef OK - -using namespace std; -using namespace dev; -using namespace dev::eth; -using namespace p2p; -using namespace boost::algorithm; -using dev::eth::Instruction; - -bool isTrue(std::string const& _m) -{ - return _m == "on" || _m == "yes" || _m == "true" || _m == "1"; -} - -bool isFalse(std::string const& _m) -{ - return _m == "off" || _m == "no" || _m == "false" || _m == "0"; -} - -void help() -{ - cout - << "Usage neth [OPTIONS]" << endl - << "Options:" << endl - << " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl - << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl - << " -B,--block-fees Set the block fee profit in the reference unit e.g. ¢ (Default: 15)." << endl - << " -c,--client-name Add a name to your client's version string (default: blank)." << endl - << " -d,--db-path Load database from path (default: ~/.ethereum " << endl - << " /Etherum or Library/Application Support/Ethereum)." << endl - << " -D,--initdag Initialize DAG for mining and exit." << endl - << " -e,--ether-price Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << endl - << " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl - << " -h,--help Show this help message and exit." << endl -#if ETH_JSONRPC - << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl - << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl -#endif - << " -K,--kill-blockchain First kill the blockchain." << endl - << " --listen-ip Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl - << " -l,--listen Listen on the given port for incoming connections (default: 30303)." << endl - << " -u,--public-ip Force public ip to given (default; auto)." << endl - << " -m,--mining Enable mining (default: off)" << endl - << " -n,--upnp Use upnp for NAT (default: on)." << endl - << " -o,--mode Start a full node or a peer node (Default: full)." << endl - << " -p,--port Connect to remote port (default: 30303)." << endl - << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl - << " -r,--remote Connect to remote host (default: none)." << endl - << " -s,--secret Set the secret key for use with send command (default: auto)." << endl - << " -t,--miners Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl - << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl - << " -x,--peers Attempt to connect to given number of peers (default: 5)." << endl - << " -V,--version Show the version and exit." << endl -#if ETH_EVMJIT - << " --vm Select VM. Options are: interpreter, jit, smart. (default: interpreter)" << endl -#endif - ; - exit(0); -} - -void interactiveHelp() -{ - cout - << "Commands:" << endl - << " netstart Starts the network sybsystem on a specific port." << endl - << " netstop Stops the network subsystem." << endl -#if ETH_JSONRPC - << " jsonstart Starts the JSON-RPC server." << endl - << " jsonstop Stops the JSON-RPC server." << endl -#endif - << " connect Connects to a specific peer." << endl - << " minestart Starts mining." << endl - << " minestop Stops mining." << endl - << " address Gives the current address." << endl - << " secret Gives the current secret" << endl - << " block Gives the current block height." << endl - << " balance Gives the current balance." << endl - << " peers List the peers that are connected" << endl - << " transact Execute a given transaction." << endl - << " send Execute a given transaction with current secret." << endl - << " contract Create a new contract with current secret." << endl - << " inspect Dumps a contract to /.evm." << endl - << " verbosity () Gets or sets verbosity level." << endl - << " setblockfees Set the block fee profit in the reference unit e.g. ¢ (Default: 15)" << endl - << " setetherprice

    Resets the ether price." << endl - << " setpriority

    Resets the transaction priority." << endl - << " reset Resets ncurses windows" << endl - << " exit Exits the application." << endl; -} - -string credits() -{ - std::ostringstream ccout; - ccout - << "NEthereum (++) " << dev::Version << endl - << " Code by Gav Wood & caktux, (c) 2013, 2014, 2015." << endl - << " Based on a design by Vitalik Buterin." << endl << endl; - - ccout << "Type 'netstart 30303' to start networking" << endl; - ccout << "Type 'connect " << Host::pocHost() << " 30303' to connect" << endl; - ccout << "Type 'exit' to quit" << endl << endl; - return ccout.str(); -} - -void version() -{ - cout << "neth version " << dev::Version << endl; - cout << "eth network protocol version: " << dev::eth::c_protocolVersion << endl; - cout << "Client database version: " << dev::eth::c_databaseVersion << endl; - cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; - exit(0); -} - -Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); -string pretty(h160 _a, dev::eth::State _st) -{ - string ns; - h256 n; - if (h160 nameReg = (u160)_st.storage(c_config, 0)) - n = _st.storage(nameReg, (u160)(_a)); - if (n) - { - std::string s((char const*)n.data(), 32); - if (s.find_first_of('\0') != string::npos) - s.resize(s.find_first_of('\0')); - ns = " " + s; - } - return ns; -} - -bool g_exit = false; - -void sighandler(int) -{ - g_exit = true; -} - -namespace nc -{ - -class nc_window_streambuf: public std::streambuf -{ -public: - nc_window_streambuf(WINDOW* p, std::ostream& os, unsigned long cursesAttr = 0); - nc_window_streambuf(WINDOW* p, unsigned long _cursesAttr = 0); - nc_window_streambuf(nc_window_streambuf const& _rhs); - virtual ~nc_window_streambuf(); - - nc_window_streambuf& operator=(nc_window_streambuf const& _rhs); - - virtual int overflow(int c); - virtual int sync(); - -private: - void copy(nc_window_streambuf const& _rhs); - - WINDOW* m_pnl; - unsigned long m_flags; - std::ostream* m_os; - std::streambuf* m_old; -}; - -nc_window_streambuf::nc_window_streambuf(WINDOW * p, unsigned long _cursesAttr): - m_pnl(p), - m_flags(_cursesAttr), - m_os(0), - m_old(0) -{ - // Tell parent class that we want to call overflow() for each - // input char: - setp(0, 0); - setg(0, 0, 0); - scrollok(p, true); - mvwinch(p, 0, 0); -} - -nc_window_streambuf::nc_window_streambuf(WINDOW* _p, std::ostream& _os, unsigned long _cursesAttr): - m_pnl(_p), - m_flags(_cursesAttr), - m_os(&_os), - m_old(_os.rdbuf()) -{ - setp(0, 0); - setg(0, 0, 0); - _os.rdbuf(this); - scrollok(_p, true); - mvwinch(_p, 0, 0); -} - -void nc_window_streambuf::copy(nc_window_streambuf const& _rhs) -{ - if (this != &_rhs) - { - m_pnl = _rhs.m_pnl; - m_flags = _rhs.m_flags; - m_os = _rhs.m_os; - m_old = _rhs.m_old; - } -} - -nc_window_streambuf::nc_window_streambuf(nc_window_streambuf const& _rhs): - std::streambuf() -{ - copy(_rhs); -} - -nc_window_streambuf& nc_window_streambuf::operator=(nc_window_streambuf const& _rhs) -{ - copy(_rhs); - return *this; -} - -nc_window_streambuf::~nc_window_streambuf() -{ - if (m_os) - m_os->rdbuf(m_old); -} - -int nc_window_streambuf::overflow(int c) -{ - int ret = c; - if (c != EOF) - { - int x = 0; - int y = 0; - int mx = 0; - int my = 0; - getyx(m_pnl, y, x); - getmaxyx(m_pnl, my, mx); - if (y < 1) - y = 1; - if (x < 2) - x = 2; - if (x > mx - 4) - { - if (y + 1 >= my) - scroll(m_pnl); - else - y++; - x = 2; - } - if (m_flags) - { - wattron(m_pnl, m_flags); - if (mvwaddch(m_pnl, y, x++, (chtype)c) == ERR) - ret = EOF; - wattroff(m_pnl, m_flags); - } - else if (mvwaddch(m_pnl, y, x++, (chtype)c) == ERR) - ret = EOF; - } - if (c == EOF) // || std::isspace(c) - if (sync() == EOF) - ret = EOF; - return ret; -} - -int nc_window_streambuf::sync() -{ - if (stdscr && m_pnl) - return (wrefresh(m_pnl) == ERR) ? EOF : 0; - return EOF; -} - -} - -vector form_dialog(vector _sfields, vector _lfields, vector _bfields, int _cols, int _rows, string _post_form); - -enum class NodeMode -{ - PeerServer, - Full -}; - -int main(int argc, char** argv) -{ - string listenIP; - unsigned short listenPort = 30303; - string publicIP; - string remoteHost; - unsigned short remotePort = 30303; - string dbPath; - unsigned mining = ~(unsigned)0; - NodeMode mode = NodeMode::Full; - unsigned peers = 5; -#if ETH_JSONRPC - int jsonrpc = 8080; -#endif - bool bootstrap = false; - bool upnp = true; - bool forceMining = false; - bool killChain = false; - bool structuredLogging = false; - string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S"; - string clientName; - TransactionPriority priority = TransactionPriority::Medium; - double etherPrice = 30.679; - double blockFees = 15.0; - - // Init defaults - Defaults::get(); - - // Our address. - KeyPair us = KeyPair::create(); - Address coinbase = us.address(); - - string configFile = getDataDir() + "/config.rlp"; - bytes b = contents(configFile); - if (b.size()) - { - RLP config(b); - us = KeyPair(config[0].toHash()); - coinbase = config[1].toHash

    (); - } - else - writeFile(configFile, rlpList(us.secret(), coinbase)); - - for (int i = 1; i < argc; ++i) - { - string arg = argv[i]; - if (arg == "--listen-ip" && i + 1 < argc) - listenIP = argv[++i]; - else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) - listenPort = (short)atoi(argv[++i]); - else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc) - publicIP = argv[++i]; - else if ((arg == "-r" || arg == "--remote") && i + 1 < argc) - remoteHost = argv[++i]; - else if ((arg == "-p" || arg == "--port") && i + 1 < argc) - remotePort = (short)atoi(argv[++i]); - else if ((arg == "-n" || arg == "--upnp") && i + 1 < argc) - { - string m = argv[++i]; - if (isTrue(m)) - upnp = true; - else if (isFalse(m)) - upnp = false; - else - { - cerr << "Invalid UPnP option: " << m << endl; - return -1; - } - } - else if (arg == "-K" || arg == "--kill-blockchain") - killChain = true; - else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) - clientName = argv[++i]; - else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) - { - try - { - coinbase = h160(fromHex(argv[++i], WhenError::Throw)); - } - catch (BadHexCharacter& _e) - { - cwarn << "invalid hex character, coinbase rejected"; - cwarn << boost::diagnostic_information(_e); - break; - } - catch (...) - { - cwarn << "coinbase rejected"; - break; - } - } - else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) - us = KeyPair(h256(fromHex(argv[++i]))); - else if (arg == "--structured-logging-format" && i + 1 < argc) - structuredLoggingFormat = string(argv[++i]); - else if (arg == "--structured-logging") - structuredLogging = true; - else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) - dbPath = argv[++i]; - else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) - { - try - { - blockFees = stof(argv[++i]); - } - catch (...) - { - cerr << "Bad " << arg << " option: " << argv[++i] << endl; - return -1; - } - } - else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc) - { - try - { - etherPrice = stof(argv[++i]); - } - catch (...) - { - cerr << "Bad " << arg << " option: " << argv[++i] << endl; - return -1; - } - } - else if ((arg == "-P" || arg == "--priority") && i + 1 < argc) - { - string m = boost::to_lower_copy(string(argv[++i])); - if (m == "lowest") - priority = TransactionPriority::Lowest; - else if (m == "low") - priority = TransactionPriority::Low; - else if (m == "medium" || m == "mid" || m == "default" || m == "normal") - priority = TransactionPriority::Medium; - else if (m == "high") - priority = TransactionPriority::High; - else if (m == "highest") - priority = TransactionPriority::Highest; - else - try { - priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100); - } - catch (...) { - cerr << "Unknown " << arg << " option: " << m << endl; - return -1; - } - } - else if ((arg == "-m" || arg == "--mining") && i + 1 < argc) - { - string m = argv[++i]; - if (isTrue(m)) - mining = ~(unsigned)0; - else if (isFalse(m)) - mining = 0; - else - try { - mining = stoi(m); - } - catch (...) { - cerr << "Unknown -m/--mining option: " << m << endl; - return -1; - } - } - else if (arg == "-b" || arg == "--bootstrap") - bootstrap = true; - else if (arg == "-f" || arg == "--force-mining") - forceMining = true; -#if ETH_JSONRPC - else if ((arg == "-j" || arg == "--json-rpc")) - jsonrpc = jsonrpc ? jsonrpc : 8080; - else if (arg == "--json-rpc-port" && i + 1 < argc) - jsonrpc = atoi(argv[++i]); -#endif - else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc) - g_logVerbosity = atoi(argv[++i]); - else if ((arg == "-x" || arg == "--peers") && i + 1 < argc) - peers = atoi(argv[++i]); - else if ((arg == "-o" || arg == "--mode") && i + 1 < argc) - { - string m = argv[++i]; - if (m == "full") - mode = NodeMode::Full; - else if (m == "peer") - mode = NodeMode::PeerServer; - else - { - cerr << "Unknown mode: " << m << endl; - return -1; - } - } -#if ETH_EVMJIT - else if (arg == "--vm" && i + 1 < argc) - { - string vmKind = argv[++i]; - if (vmKind == "interpreter") - VMFactory::setKind(VMKind::Interpreter); - else if (vmKind == "jit") - VMFactory::setKind(VMKind::JIT); - else if (vmKind == "smart") - VMFactory::setKind(VMKind::Smart); - else - { - cerr << "Unknown VM kind: " << vmKind << endl; - return -1; - } - } -#endif - else if (arg == "-h" || arg == "--help") - help(); - else if (arg == "-V" || arg == "--version") - version(); - else - { - cerr << "Invalid argument: " << arg << endl; - exit(-1); - } - } - - if (!clientName.empty()) - clientName += "/"; - - cout << credits(); - - StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); - auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); - auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); - std::string clientImplString = "N++eth/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM)); - dev::WebThreeDirect web3( - clientImplString, - dbPath, - killChain ? WithExisting::Kill : WithExisting::Trust, - mode == NodeMode::Full ? set{"eth", "shh"} : set(), - netPrefs, - &nodesState); - - web3.setIdealPeerCount(peers); - std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); - eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr; - StructuredLogger::starting(clientImplString, dev::Version); - if (c) - { - c->setGasPricer(gasPricer); - c->setForceMining(forceMining); - c->setAddress(coinbase); - } - - cout << "Transaction Signer: " << us.address() << endl; - cout << "Mining Benefactor: " << coinbase << endl; - web3.startNetwork(); - - if (bootstrap) - web3.addNode(p2p::NodeId(), Host::pocHost()); - if (remoteHost.size()) - web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); - if (c && mining) - c->startMining(); - -#if ETH_JSONRPC || !ETH_TRUE - shared_ptr jsonrpcServer; - unique_ptr jsonrpcConnector; - KeyManager km; - if (jsonrpc > -1) - { - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, vector({us})), vector({us})), km); - jsonrpcServer->setIdentities({us}); - jsonrpcServer->StartListening(); - } -#endif - - signal(SIGABRT, &sighandler); - signal(SIGTERM, &sighandler); - signal(SIGINT, &sighandler); - - std::ostringstream ccout; - - // Initialize ncurses - char* str = new char[255]; - int width; - int height; - int y = 0; - int x = 2; - string cmd; - WINDOW * mainwin, * consolewin, * logwin, * blockswin, * pendingwin, *addswin, * contractswin, * peerswin; - - if (!(mainwin = initscr())) - { - cerr << "Error initialising ncurses."; - delete [] str; - return -1; - } - - getmaxyx(mainwin, height, width); - int qheight = height * 3 / 5; - int qwidth = width / 4 - 4; - - nonl(); - cbreak(); - timeout(30000); - echo(); - keypad(mainwin, true); - - // Initialize color pairs - start_color(); - init_pair(1, COLOR_WHITE, COLOR_BLACK); - init_pair(2, COLOR_RED, COLOR_BLACK); - init_pair(3, 7, COLOR_BLACK); - use_default_colors(); - - logwin = newwin(height * 2 / 5 - 2, width * 2 / 3, qheight, 0); - nc::nc_window_streambuf outbuf(logwin, std::cout); - nc::nc_window_streambuf eoutbuf(logwin, std::cerr); - - consolewin = newwin(qheight, width / 4, 0, 0); - nc::nc_window_streambuf coutbuf(consolewin, ccout); - blockswin = newwin(qheight, width / 4, 0, width / 4); - pendingwin = newwin(height * 1 / 5, width / 4, 0, width * 2 / 4); - peerswin = newwin(height * 2 / 5, width / 4, height * 1 / 5, width * 2 / 4); - addswin = newwin(height * 2 / 5 - 2, width / 3, qheight, width * 2 / 3); - contractswin = newwin(qheight, width / 4, 0, width * 3 / 4); - - int vl = qheight - 4; - wsetscrreg(consolewin, 1, vl); - wsetscrreg(blockswin, 1, vl); - wsetscrreg(pendingwin, 1, vl); - wsetscrreg(peerswin, 1, vl); - wsetscrreg(addswin, 1, vl); - wsetscrreg(contractswin, 1, vl); - - mvwprintw(mainwin, 1, 1, " > "); - wresize(mainwin, 3, width); - mvwin(mainwin, height - 3, 0); - - wmove(mainwin, 1, 4); - - while (true) - { - wclrtobot(consolewin); - wclrtobot(pendingwin); - wclrtobot(peerswin); - wclrtobot(addswin); - wclrtobot(contractswin); - - ccout << credits(); - - // Prompt - wmove(mainwin, 1, 4); - getstr(str); - - string s(str); - istringstream iss(s); - iss >> cmd; - - // Address - ccout << "Address:" << endl; - ccout << toHex(us.address().asArray()) << endl << endl; - - mvwprintw(mainwin, 1, 1, " > "); - clrtoeol(); - - if (s.length() > 1) - { - ccout << "> "; - ccout << str << endl; - } - - if (cmd == "netstart") - { - unsigned port; - iss >> port; - if (port) - netPrefs.listenPort = port; - web3.setNetworkPreferences(netPrefs); - web3.startNetwork(); - } - else if (cmd == "connect") - { - string addr; - unsigned port; - iss >> addr >> port; - web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort)); - } - else if (cmd == "netstop") - { - web3.stopNetwork(); - } - else if (c && cmd == "minestart") - { - c->startMining(); - } - else if (c && cmd == "minestop") - { - c->stopMining(); - } - else if (c && cmd == "mineforce") - { - string enable; - iss >> enable; - c->setForceMining(isTrue(enable)); - } - else if (c && cmd == "setblockfees") - { - iss >> blockFees; - try - { - gasPricer->setRefBlockFees(u256(blockFees * 1000)); - } - catch (Overflow const& _e) - { - cout << boost::diagnostic_information(_e); - } - - cout << "Block fees: " << blockFees << endl; - } - else if (c && cmd == "setetherprice") - { - iss >> etherPrice; - if (etherPrice == 0) - cout << "ether price cannot be set to zero" << endl; - else - { - try - { - gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice)); - } - catch (Overflow const& _e) - { - cout << boost::diagnostic_information(_e); - } - } - cout << "ether Price: " << etherPrice << endl; - } - else if (c && cmd == "setpriority") - { - string m; - iss >> m; - boost::to_lower(m); - if (m == "lowest") - priority = TransactionPriority::Lowest; - else if (m == "low") - priority = TransactionPriority::Low; - else if (m == "medium" || m == "mid" || m == "default" || m == "normal") - priority = TransactionPriority::Medium; - else if (m == "high") - priority = TransactionPriority::High; - else if (m == "highest") - priority = TransactionPriority::Highest; - else - try { - priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100); - } - catch (...) { - cerr << "Unknown priority: " << m << endl; - } - cout << "Priority: " << (int)priority << "/8" << endl; - } - else if (cmd == "verbosity") - { - if (iss.peek() != -1) - iss >> g_logVerbosity; - cout << "Verbosity: " << g_logVerbosity << endl; - } -#if ETH_JSONRPC - else if (cmd == "jsonport") - { - if (iss.peek() != -1) - iss >> jsonrpc; - cout << "JSONRPC Port: " << jsonrpc << endl; - } - else if (cmd == "jsonstart") - { - if (jsonrpc < 0) - jsonrpc = 8080; -#if ETH_DEBUG - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", 1)); -#else - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", 4)); -#endif - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, vector({us})), vector({us}))); - jsonrpcServer->setIdentities({us}); - jsonrpcServer->StartListening(); - } - else if (cmd == "jsonstop") - { - if (jsonrpcServer.get()) - jsonrpcServer->StopListening(); - jsonrpcServer.reset(); - } -#endif - else if (cmd == "address") - { - ccout << "Current address:" << endl; - ccout << toHex(us.address().asArray()) << endl; - } - else if (cmd == "secret") - { - ccout << "Current secret:" << endl; - ccout << toHex(us.secret().asArray()) << endl; - } - else if (c && cmd == "block") - { - unsigned n = c->blockChain().details().number; - ccout << "Current block # "; - ccout << toString(n) << endl; - } - else if (cmd == "peers") - { - for (auto it: web3.peers()) - cout << it.host << ":" << it.port << ", " << it.clientVersion << ", " - << std::chrono::duration_cast(it.lastPing).count() << "ms" - << endl; - } - else if (c && cmd == "balance") - { - u256 balance = c->balanceAt(us.address()); - ccout << "Current balance:" << endl; - ccout << toString(balance) << endl; - } - else if (c && cmd == "transact") - { - auto const& bc = c->blockChain(); - auto h = bc.currentHash(); - auto blockData = bc.block(h); - BlockInfo info(blockData); - vector s; - s.push_back("Address"); - vector l; - l.push_back("Amount"); - stringstream label; - label << "Gas price"; - l.push_back(label.str()); - l.push_back("Gas"); - vector b; - b.push_back("Secret"); - b.push_back("Data"); - vector fields = form_dialog(s, l, b, height, width, cmd); - int fs = fields.size(); - if (fs < 6) - { - if (fs > 0) - cwarn << "Missing parameter"; - } - else - { - fields[0].erase(std::remove(fields[0].begin(), fields[0].end(), ' '), fields[0].end()); - fields[4].erase(std::remove(fields[4].begin(), fields[4].end(), ' '), fields[4].end()); - fields[5].erase(std::find_if(fields[5].rbegin(), fields[5].rend(), std::bind1st(std::not_equal_to(), ' ')).base(), fields[5].end()); - int size = fields[0].length(); - u256 amount; - u256 gasPrice; - u256 gas; - stringstream ssa; - ssa << fields[1]; - ssa >> amount; - stringstream ssg; - ssg << fields[3]; - ssg >> gas; - stringstream ssp; - ssp << fields[2]; - ssp >> gasPrice; - if (!gasPrice) - gasPrice = gasPricer->bid(priority); - string sechex = fields[4]; - string sdata = fields[5]; - cnote << "Data:"; - cnote << sdata; - bytes data = dev::eth::parseData(sdata); - cnote << "Bytes:"; - string sbd = asString(data); - bytes bbd = asBytes(sbd); - stringstream ssbd; - ssbd << bbd; - cnote << ssbd.str(); - int ssize = fields[4].length(); - u256 minGas = (u256)Transaction::gasRequired(data, 0); - if (size < 40) - { - if (size > 0) - cwarn << "Invalid address length:" << size; - } - else if (gas < minGas) - cwarn << "Minimum gas amount is" << minGas; - else if (ssize < 40) - { - if (ssize > 0) - cwarn << "Invalid secret length:" << ssize; - } - else - { - try - { - Secret secret = h256(fromHex(sechex, WhenError::Throw)); - Address dest = h160(fromHex(fields[0], WhenError::Throw)); - c->submitTransaction(secret, amount, dest, data, gas, gasPrice); - } - catch (BadHexCharacter& _e) - { - cwarn << "invalid hex character, transaction rejected"; - cwarn << boost::diagnostic_information(_e); - } - catch (...) - { - cwarn << "transaction rejected"; - } - } - } - } - else if (c && cmd == "send") - { - vector s; - s.push_back("Address"); - vector l; - l.push_back("Amount"); - vector b; - vector fields = form_dialog(s, l, b, height, width, cmd); - int fs = fields.size(); - if (fs < 2) - { - if (fs > 0) - cwarn << "Missing parameter"; - } - else - { - fields[0].erase(std::remove(fields[0].begin(), fields[0].end(), ' '), fields[0].end()); - int size = fields[0].length(); - u256 amount; - stringstream sss; - sss << fields[1]; - sss >> amount; - if (size < 40) - { - if (size > 0) - cwarn << "Invalid address length:" << size; - } - else - { - auto const& bc = c->blockChain(); - auto h = bc.currentHash(); - auto blockData = bc.block(h); - BlockInfo info(blockData); - u256 minGas = (u256)Transaction::gasRequired(bytes(), 0); - try - { - Address dest = h160(fromHex(fields[0], WhenError::Throw)); - c->submitTransaction(us.secret(), amount, dest, bytes(), minGas); - } - catch (BadHexCharacter& _e) - { - cwarn << "invalid hex character, transaction rejected"; - cwarn << boost::diagnostic_information(_e); - } - catch (...) - { - cwarn << "transaction rejected"; - } - } - } - } - else if (c && cmd == "contract") - { - auto const& bc = c->blockChain(); - auto h = bc.currentHash(); - auto blockData = bc.block(h); - BlockInfo info(blockData); - vector s; - vector l; - l.push_back("Endowment"); - stringstream label; - label << "Gas price"; - l.push_back(label.str()); - l.push_back("Gas"); - vector b; - b.push_back("Code (hex)"); - vector fields = form_dialog(s, l, b, height, width, cmd); - int fs = fields.size(); - if (fs < 4) - { - if (fs > 0) - cwarn << "Missing parameter"; - } - else - { - u256 endowment; - u256 gas; - u256 gasPrice; - stringstream sse; - sse << fields[0]; - sse >> endowment; - stringstream ssg; - ssg << fields[2]; - ssg >> gas; - stringstream ssp; - ssp << fields[1]; - ssp >> gasPrice; - string sinit = fields[3]; - trim_all(sinit); - int size = sinit.length(); - bytes init; - cnote << "Init:"; - cnote << sinit; - cnote << "Code size:" << size; - if (size < 1) - cwarn << "No code submitted"; - else - { - cnote << "Assembled:"; - stringstream ssc; - try - { - init = fromHex(sinit, WhenError::Throw); - } - catch (BadHexCharacter& _e) - { - cwarn << "invalid hex character, code rejected"; - cwarn << boost::diagnostic_information(_e); - init = bytes(); - } - catch (...) - { - cwarn << "code rejected"; - init = bytes(); - } - - ssc.str(string()); - ssc << disassemble(init); - cnote << "Init:"; - cnote << ssc.str(); - } - u256 minGas = (u256)Transaction::gasRequired(init, 0); - if (!init.size()) - cwarn << "Contract creation aborted, no init code."; - else if (endowment < 0) - cwarn << "Invalid endowment"; - else if (gas < minGas) - cwarn << "Minimum gas amount is" << minGas; - else - c->submitTransaction(us.secret(), endowment, init, gas); - } - } - else if (c && cmd == "inspect") - { - string rechex; - iss >> rechex; - - if (rechex.length() != 40) - cwarn << "Invalid address length"; - else - { - auto address = h160(fromHex(rechex)); - stringstream s; - - try - { - auto storage = c->storageAt(address); - for (auto const& i: storage) - s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl; - s << endl << disassemble(c->codeAt(address)) << endl; - - string outFile = getDataDir() + "/" + rechex + ".evm"; - ofstream ofs; - ofs.open(outFile, ofstream::binary); - ofs.write(s.str().c_str(), s.str().length()); - ofs.close(); - - cnote << "Saved" << rechex << "to" << outFile; - } - catch (dev::InvalidTrie const& _e) - { - cwarn << "Corrupted trie.\n" << diagnostic_information(_e); - } - } - } - else if (cmd == "reset") - { - vector ws { consolewin, blockswin, pendingwin, peerswin, contractswin, addswin, mainwin }; - for (auto &w: ws) - { - wclear(w); - wrefresh(w); - } - } - else if (cmd == "help") - interactiveHelp(); - else if (cmd == "exit") - break; - else if (cmd != "") - cwarn << "Unrecognised command. Type 'help' for a list of available commands."; - - // Clear cmd at each pass - cmd = ""; - - - // Contracts and addresses count / offset - int cc = 1; - int ca = 0; - - if (c) { - // Lock to prevent corrupt block-chain errors - auto const& bc = c->blockChain(); - ccout << "Genesis hash: " << bc.genesisHash() << endl; - - // Blocks - y = 1; - for (auto h = bc.currentHash(); h != bc.genesisHash(); h = bc.details(h).parent) - { - auto d = bc.details(h); - string s = "# " + std::to_string(d.number) + ' ' + toString(h); // .abridged(); - mvwaddnstr(blockswin, y++, x, s.c_str(), qwidth); - - auto b = bc.block(h); - for (auto const& i: RLP(b)[1]) - { - Transaction t(i.data(), CheckTransaction::Everything); - auto s = t.receiveAddress() ? - boost::format(" %1% %2%> %3%: %4% [%5%]") % - toString(t.safeSender()) % - (c->codeAt(t.receiveAddress(), PendingBlock).size() ? '*' : '-') % - toString(t.receiveAddress()) % - toString(formatBalance(t.value())) % - toString((unsigned)t.nonce()) : - boost::format(" %1% +> %2%: %3% [%4%]") % - toString(t.safeSender()) % - toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) % - toString(formatBalance(t.value())) % - toString((unsigned)t.nonce()); - mvwaddnstr(blockswin, y++, x, s.str().c_str(), qwidth - 2); - if (y > qheight - 2) - break; - } - if (y > qheight - 2) - break; - } - - - // Pending - y = 1; - for (Transaction const& t: c->pending()) - { - auto s = t.receiveAddress() ? - boost::format("%1% %2%> %3%: %4% [%5%]") % - toString(t.safeSender()) % - (c->codeAt(t.receiveAddress(), PendingBlock).size() ? '*' : '-') % - toString(t.receiveAddress()) % - toString(formatBalance(t.value())) % - toString((unsigned)t.nonce()) : - boost::format("%1% +> %2%: %3% [%4%]") % - toString(t.safeSender()) % - toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) % - toString(formatBalance(t.value())) % - toString((unsigned)t.nonce()); - mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth); - if (y > height * 1 / 5 - 2) - break; - } - -#if ETH_FATDB - // Contracts and addresses - y = 1; - auto acs = c->addresses(); - ca = acs.size(); - for (auto const& i: acs) - if (c->codeAt(i, PendingBlock).size()) - { - auto s = boost::format("%1%%2% : %3% [%4%]") % - toString(i) % - pretty(i, c->postState()) % - toString(formatBalance(c->balanceAt(i))) % - toString((unsigned)c->countAt(i, PendingBlock)); - mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth); - if (cc > qheight - 2) - break; - } - for (auto const& i: acs) - if (c->codeAt(i, PendingBlock).empty()) - { - auto s = boost::format("%1%%2% : %3% [%4%]") % - toString(i) % - pretty(i, c->postState()) % - toString(formatBalance(c->balanceAt(i))) % - toString((unsigned)c->countAt(i, PendingBlock)); - mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4); - if (y > height * 3 / 5 - 4) - break; - } -#else - mvwaddnstr(contractswin, 1, x, "build with ETH_FATDB to list contracts", qwidth); - mvwaddnstr(addswin, 1, x, "build with ETH_FATDB to list addresses", width / 2 - 4); -#endif - - // Peers - y = 1; - for (PeerSessionInfo const& i: web3.peers()) - { - auto s = boost::format("%1% ms - %2%:%3% - %4%") % - toString(chrono::duration_cast(i.lastPing).count()) % - i.host % - toString(i.port) % - i.clientVersion; - mvwaddnstr(peerswin, y++, x, s.str().c_str(), qwidth); - if (y > height * 2 / 5 - 4) - break; - } - } - - box(consolewin, 0, 0); - box(blockswin, 0, 0); - box(pendingwin, 0, 0); - box(peerswin, 0, 0); - box(addswin, 0, 0); - box(contractswin, 0, 0); - box(mainwin, 0, 0); - - // Balance - stringstream ssb; - u256 balance; - if (c) - balance = c->balanceAt(us.address()); - ssb << "Balance: "; - if (c) - ssb << formatBalance(balance); - mvwprintw(consolewin, 0, x, ssb.str().c_str()); - - // Block - mvwprintw(blockswin, 0, x, "Block # "); - if (c) { - unsigned n = c->blockChain().details().number; - mvwprintw(blockswin, 0, 10, toString(n).c_str()); - } - - // Pending - stringstream pc; - pc << "Pending: "; - if (c) - pc << toString(c->pending().size()); - else - pc << 0; - mvwprintw(pendingwin, 0, x, pc.str().c_str()); - - // Contracts - stringstream sc; - sc << "Contracts: " << cc - 1; - mvwprintw(contractswin, 0, x, sc.str().c_str()); - - // Peers - mvwprintw(peerswin, 0, x, "Peers: "); - mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str()); - - // Mining flag - if (c && c->isMining()) - { - mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON"); - dev::eth::MiningProgress p = c->miningProgress(); - auto speed = boost::format("%2% kH/s @ %1%s") % (p.ms / 1000) % (p.ms ? p.hashes / p.ms : 0); - mvwprintw(consolewin, qheight - 2, width / 4 - speed.str().length() - 2, speed.str().c_str()); - } - else - mvwprintw(consolewin, qheight - 1, width / 4 - 12, "Mining OFF"); - - wmove(consolewin, 1, x); - - // Addresses - stringstream ac; - ac << "Addresses: " << ca; - mvwprintw(addswin, 0, x, ac.str().c_str()); - - - wrefresh(consolewin); - wrefresh(blockswin); - wrefresh(pendingwin); - wrefresh(peerswin); - wrefresh(addswin); - wrefresh(contractswin); - wrefresh(mainwin); - } - - delwin(addswin); - delwin(contractswin); - delwin(peerswin); - delwin(pendingwin); - delwin(blockswin); - delwin(consolewin); - delwin(logwin); - delwin(mainwin); - endwin(); - refresh(); - -#if ETH_JSONRPC - if (jsonrpcServer.get()) - jsonrpcServer->StopListening(); -#endif - - return 0; -} - -void print_in_middle(WINDOW *win, int starty, int startx, int width, string str, chtype color) -{ - int length; - int x = 0; - int y = 0; - float temp; - - if (startx != 0) - x = startx; - if (starty != 0) - y = starty; - if (width == 0) - width = 80; - - length = str.length(); - temp = (width - length) / 2; - x = x + (int)temp; - wattron(win, color); - mvwprintw(win, y, x, "%s", str.c_str()); - wattroff(win, color); - refresh(); -} - -vector form_dialog(vector _sv, vector _lv, vector _bv, int _cols, int _rows, string _post_form) -{ - vector vs; - WINDOW *form_win; - int _sfields = _sv.size(); - int _lfields = _lv.size(); - int _bfields = _bv.size(); - int maxfields = _sfields + _lfields + _bfields; - vector field(maxfields + 1); - - int ch; - int starty = 6; - int height = _cols; - int width = _rows; - - // Initialize the fields - int si; - int li; - int bi = 0; - vector labels; - for (si = 0; si < _sfields; ++si) - { - starty++; // Leave room for our labels, no window yet so that or fake fields... - field[si] = new_field(1, 40, starty++, 1, 0, 0); - labels.push_back(starty); - set_field_back(field[si], A_UNDERLINE); - set_field_type(field[si], TYPE_ALNUM, 40); - } - for (li = _sfields; li < _sfields + _lfields; ++li) - { - starty++; - field[li] = new_field(1, 64, starty++, 1, 3, 0); - labels.push_back(starty); - set_field_back(field[li], A_UNDERLINE); - } - for (bi = _sfields + _lfields; bi < maxfields; ++bi) - { - starty++; - field[bi] = new_field(5, 72, starty++, 1, 0, 0); - labels.push_back(starty); - field_opts_off(field[bi], O_STATIC); - set_field_back(field[bi], A_UNDERLINE); - starty += 4; - } - - // The FORM expects a NULL terminated list of fields - field[maxfields] = NULL; - - // Create the form and post it - FORM *form = new_form(field.data()); - - // Calculate the area required for the form - scale_form(form, &_rows, &_cols); - - // Create the window to be associated with the form - form_win = newwin(_rows + 4, _cols + 8, (height / 2 - _rows / 2 - 2), (width / 2 - _cols / 2 - 2)); - - // Set main window and sub window - set_form_win(form, form_win); - set_form_sub(form, derwin(form_win, _rows, _cols, 2, 2)); - - nodelay(form_win, true); - keypad(form_win, true); - noecho(); - timeout(0); - - box(form_win, 0, 0); - print_in_middle(form_win, 1, 0, _cols, _post_form, COLOR_PAIR(2)); - - post_form(form); - - // Set labels - int ca = 0; - int cf; - for (cf = 0; cf < _sfields; ++cf) - { - wattron(form_win, COLOR_PAIR(3)); - mvwprintw(form_win, labels[ca], 3, _sv[cf].c_str()); - wattroff(form_win, COLOR_PAIR(3)); - ca++; - } - for (cf = 0; cf < _lfields; ++cf) - { - wattron(form_win, COLOR_PAIR(3)); - mvwprintw(form_win, labels[ca], 3, _lv[cf].c_str()); - mvwprintw(form_win, labels[ca] + 1, _cols - 1, "wei"); - wattroff(form_win, COLOR_PAIR(3)); - ca++; - } - for (cf = 0; cf < _bfields; ++cf) - { - wattron(form_win, COLOR_PAIR(3)); - mvwprintw(form_win, labels[ca], 3, _bv[cf].c_str()); - wattroff(form_win, COLOR_PAIR(3)); - ca++; - } - - wrefresh(form_win); - - print_in_middle(form_win, 3, 0, _cols, string("Use the TAB key to switch between fields."), COLOR_PAIR(1)); - print_in_middle(form_win, 4, 0, _cols, string("Use UP, DOWN arrow keys to switch between lines."), COLOR_PAIR(1)); - print_in_middle(form_win, 6, 0, _cols, string("Press ENTER to submit the form and ESC to cancel."), COLOR_PAIR(1)); - refresh(); - - while ((ch = wgetch(form_win)) != 27 && ch != 13) // KEY_F(1)) - { - switch (ch) - { - case 9: // Tab - form_driver(form, REQ_NEXT_FIELD); - form_driver(form, REQ_END_LINE); - break; - case KEY_DOWN: - form_driver(form, REQ_NEXT_LINE); - break; - case KEY_UP: - form_driver(form, REQ_PREV_LINE); - break; - case KEY_LEFT: - form_driver(form, REQ_LEFT_CHAR); - break; - case KEY_RIGHT: - form_driver(form, REQ_RIGHT_CHAR); - break; - case KEY_BACKSPACE: // Backspace - case KEY_DC: - case KEY_DL: - case 127: - form_driver(form, REQ_DEL_PREV); - wrefresh(form_win); - break; - case KEY_ENTER: // Enter - case 13: - case 27: // Esc - break; - default: - form_driver(form, ch); - break; - } - } - - if (form_driver(form, REQ_VALIDATION) != E_OK) - cwarn << "Validation error"; - - int fi; - for (fi = 0; fi < maxfields; ++fi) - free_field(field[fi]); - free_form(form); - unpost_form(form); - echo(); - timeout(30000); - delwin(form_win); - - if (ch == 13) - for (int fi = 0; fi < maxfields; ++fi) - vs.push_back(field_buffer(field[fi], 0)); - - return vs; -} From d59b71210dc887ac91320187506f33aab4dfd65d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Jul 2015 20:15:22 +0200 Subject: [PATCH 113/113] Version bump. --- libdevcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 6ba933556..6df0d4d69 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -28,7 +28,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.29"; +char const* Version = "0.9.30"; const u256 UndefinedU256 = ~(u256)0;