diff --git a/CMakeLists.txt b/CMakeLists.txt
index 667c2fb73..a2b31d174 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -389,23 +389,37 @@ endif()
if (WIN32)
# packaging stuff
include(InstallRequiredSystemLibraries)
- set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "ethereum")
+ set(CPACK_PACKAGE_NAME "Ethereum")
+ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ethereum")
set(CPACK_PACKAGE_VENDOR "ethereum.org")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
- set(CPACK_PACKAGE_VERSION "0.7")
+ set(CPACK_PACKAGE_VERSION "0.9")
set(CPACK_GENERATOR "NSIS")
# seems to be not working
# set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/alethzero/alethzero.bmp")
# our stuff
set(CPACK_COMPONENT_ALETHZERO_GROUP "Applications")
- set(CPACK_COMPONENT_THIRD_GROUP "Applications")
set(CPACK_COMPONENT_MIX_GROUP "Applications")
- set(CPACK_COMPONENTS_ALL alethzero third mix)
+ set(CPACK_COMPONENT_SOLC_GROUP "CLI")
+ set(CPACK_COMPONENT_ETH_GROUP "CLI")
+ set(CPACK_COMPONENT_ETHMINER_GROUP "CLI")
+ set(CPACK_COMPONENT_RLP_GROUP "CLI")
+ set(CPACK_COMPONENT_ABI_GROUP "CLI")
+
+ set(CPACK_COMPONENTS_ALL alethzero mix solc eth ethminer rlp abi)
# nsis specific stuff
- set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} ethereum")
+ if (CMAKE_CL_64)
+ set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
+ set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION} (Win64)")
+ else ()
+ set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES")
+ set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
+ endif()
+
+ set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} Ethereum")
set(CPACK_NSIS_HELP_LINK "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/ethereum/cpp-ethereum")
set(CPACK_NSIS_CONTACT "ethereum.org")
diff --git a/abi/CMakeLists.txt b/abi/CMakeLists.txt
index 82c7c4240..3cc6b2594 100644
--- a/abi/CMakeLists.txt
+++ b/abi/CMakeLists.txt
@@ -12,5 +12,8 @@ add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} ethereum)
-install( TARGETS ${EXECUTABLE} DESTINATION bin)
-
+if (APPLE)
+ install(TARGETS ${EXECUTABLE} DESTINATION bin)
+else()
+ eth_install_executable(${EXECUTABLE})
+endif()
diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp
index 7c754f8f5..a91beb2f7 100644
--- a/alethzero/DappLoader.cpp
+++ b/alethzero/DappLoader.cpp
@@ -69,7 +69,11 @@ DappLocation DappLoader::resolveAppUri(QString const& _uri)
string32 name = ZeroString32;
QByteArray utf8 = parts[partIndex].toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), name.data());
- address = abiOut
(web3()->ethereum()->call(address, abiIn("subRegistrar(bytes32)", name)).output);
+ if (address != m_nameReg)
+ address = abiOut(web3()->ethereum()->call(address, abiIn("subRegistrar(bytes32)", name)).output);
+ else
+ address = abiOut(web3()->ethereum()->call(address, abiIn("register(bytes32)", name)).output);
+
domainParts.append(parts[partIndex]);
if (!address)
{
diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index cdd734941..736af8684 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -256,6 +256,19 @@
+ -
+
+
+
+
+
+
+
+
+ Automatic
+
+
+
-
@@ -266,16 +279,6 @@
- -
-
-
- 1
-
-
- 5
-
-
-
-
@@ -289,20 +292,21 @@
- -
-
-
-
-
+
-
+
-
+ Public IP
+
+
+ -
+
Automatic
- -
+
-
Ideal &Peers
@@ -312,21 +316,7 @@
- -
-
-
- Automatic
-
-
-
- -
-
-
- Public IP
-
-
-
- -
+
-
&Client Name
@@ -336,13 +326,30 @@
- -
+
-
+
+
+ 1
+
+
+ 5
+
+
+
+ -
Anonymous
+ -
+
+
+ true
+
+
+
@@ -552,7 +559,7 @@
-
+
QDockWidget::DockWidgetFeatureMask
@@ -1751,7 +1758,6 @@ font-size: 14pt
verbosity
tabWidget
urlEdit
- idealPeers
listenIP
port
transactionQueue
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 3b89d3398..e5504cab2 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -143,11 +143,6 @@ Main::Main(QWidget *parent) :
// ui->log->addItem(QString::fromStdString(s));
};
-#if !ETH_FATDB
- delete ui->dockWidget_accounts;
- delete ui->dockWidget_contracts;
-#endif
-
#if ETH_DEBUG
m_servers.append("127.0.0.1:30300");
#endif
@@ -204,6 +199,9 @@ Main::Main(QWidget *parent) :
// QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page);
readSettings();
+#if !ETH_FATDB
+ removeDockWidget(ui->dockWidget_accounts);
+#endif
installWatches();
startTimer(100);
@@ -1373,6 +1371,8 @@ void Main::on_transactionQueue_currentItemChanged()
s << "Log Bloom: " << receipt.bloom() << "
";
else
s << "Log Bloom: Uneventful
";
+ s << "Gas Used: " << receipt.gasUsed() << "
";
+ s << "End State: " << receipt.stateRoot().abridged() << "
";
auto r = receipt.rlp();
s << "Receipt: " << toString(RLP(r)) << "
";
s << "Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
";
@@ -1566,6 +1566,8 @@ void Main::on_blocks_currentItemChanged()
s << "Log Bloom: " << receipt.bloom() << "
";
else
s << "Log Bloom: Uneventful
";
+ s << "Gas Used: " << receipt.gasUsed() << "
";
+ s << "End State: " << receipt.stateRoot().abridged() << "
";
auto r = receipt.rlp();
s << "Receipt: " << toString(RLP(r)) << "
";
s << "Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
";
@@ -1776,6 +1778,7 @@ void Main::on_net_triggered()
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
+ ui->enode->setText(QString::fromStdString(web3()->enode()));
}
else
{
diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake
index be4f7ccd1..1d1cb887b 100644
--- a/cmake/EthExecutableHelper.cmake
+++ b/cmake/EthExecutableHelper.cmake
@@ -94,6 +94,7 @@ macro(eth_install_executable EXECUTABLE)
# This tool and next will inspect linked libraries in order to determine which dependencies are required
if (${CMAKE_CFG_INTDIR} STREQUAL ".")
+ # TODO: This should only happen for GUI application
set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${EXECUTABLE}.app")
else ()
set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app")
@@ -126,8 +127,15 @@ macro(eth_install_executable EXECUTABLE)
eth_copy_dlls(${EXECUTABLE} ${dll})
endforeach(dll)
- install( TARGETS ${EXECUTABLE} RUNTIME
- DESTINATION bin
+ install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Debug"
+ DESTINATION .
+ CONFIGURATIONS Debug
+ COMPONENT ${EXECUTABLE}
+ )
+
+ install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Release"
+ DESTINATION .
+ CONFIGURATIONS Release
COMPONENT ${EXECUTABLE}
)
diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt
index 962d55373..0e56eb9f5 100644
--- a/eth/CMakeLists.txt
+++ b/eth/CMakeLists.txt
@@ -37,5 +37,8 @@ if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
-install( TARGETS ${EXECUTABLE} DESTINATION bin )
-
+if (APPLE)
+ install(TARGETS ${EXECUTABLE} DESTINATION bin)
+else()
+ eth_install_executable(${EXECUTABLE})
+endif()
diff --git a/eth/main.cpp b/eth/main.cpp
index 985e74e59..cb051aad1 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -317,8 +317,9 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u
innerMean += rate;
}
f.stop();
+ innerMean /= (_trials - 2);
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
- cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl;
+ cout << "inner mean: " << innerMean << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE
@@ -407,6 +408,7 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
int main(int argc, char** argv)
{
+#if 0
cout << "\x1b[30mEthBlack\x1b[0m" << endl;
cout << "\x1b[90mEthCoal\x1b[0m" << endl;
cout << "\x1b[37mEthGray\x1b[0m" << endl;
@@ -472,7 +474,7 @@ int main(int argc, char** argv)
cout << "\x1b[4;35mEthPurpleU\x1b[0m" << endl;
cout << "\x1b[4;36mEthCyanU\x1b[0m" << endl;
cout << "\x1b[4;37mEthWhiteU\x1b[0m" << endl;
-
+#endif
// Init defaults
Defaults::get();
@@ -1051,6 +1053,7 @@ int main(int argc, char** argv)
cout << "Transaction Signer: " << sigKey.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl;
web3.startNetwork();
+ cout << "Node ID: " << web3.enode() << endl;
if (bootstrap)
web3.addNode(p2p::NodeId(), Host::pocHost());
diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt
index cd8919bb2..af38c0c84 100644
--- a/ethminer/CMakeLists.txt
+++ b/ethminer/CMakeLists.txt
@@ -37,5 +37,9 @@ if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
-install( TARGETS ${EXECUTABLE} DESTINATION bin )
+if (APPLE)
+ install(TARGETS ${EXECUTABLE} DESTINATION bin)
+else()
+ eth_install_executable(${EXECUTABLE})
+endif()
diff --git a/ethminer/main.cpp b/ethminer/main.cpp
index 19324945f..02ccf2dd8 100644
--- a/ethminer/main.cpp
+++ b/ethminer/main.cpp
@@ -188,8 +188,9 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u
innerMean += rate;
}
f.stop();
+ innerMean /= (_trials - 2);
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
- cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl;
+ cout << "inner mean: " << innerMean << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE
diff --git a/exp/main.cpp b/exp/main.cpp
index 366c5b2ff..973679f3d 100644
--- a/exp/main.cpp
+++ b/exp/main.cpp
@@ -33,6 +33,7 @@
#endif
#include
#include
+#include
#include
#include
#include
@@ -43,6 +44,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -58,8 +60,94 @@ using namespace dev::eth;
using namespace dev::p2p;
using namespace dev::shh;
namespace js = json_spirit;
+namespace fs = boost::filesystem;
-#if 0
+#if 1
+
+inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); }
+
+class KeyManager: public Worker
+{
+public:
+ KeyManager() { readKeys(); }
+ ~KeyManager() {}
+
+ Secret secret(h128 const& _uuid, std::string const& _pass)
+ {
+ auto it = m_keys.find(_uuid);
+ if (it == m_keys.end())
+ return Secret();
+ return Secret(decrypt(it->second, _pass));
+ }
+
+private:
+ void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
+ {
+ fs::path p(_keysPath);
+ js::mValue v;
+ for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
+ if (is_regular_file(it->path()))
+ {
+ cdebug << "Reading" << it->path();
+ js::read_string(contentsString(it->path().string()), v);
+ js::mObject o = v.get_obj();
+ int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0;
+ if (version == 2)
+ m_keys[fromUUID(o["id"].get_str())] = o["crypto"];
+ else
+ cwarn << "Cannot read key version" << version;
+ }
+ }
+
+ static bytes decrypt(js::mValue const& _v, std::string const& _pass)
+ {
+ js::mObject o = _v.get_obj();
+ bytes pKey;
+ if (o["kdf"].get_str() == "pbkdf2")
+ {
+ auto params = o["kdfparams"].get_obj();
+ unsigned iterations = params["c"].get_int();
+ bytes salt = fromHex(params["salt"].get_str());
+ pKey = pbkdf2(_pass, salt, iterations).asBytes();
+ }
+ else
+ {
+ cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
+ return bytes();
+ }
+
+ // TODO check MAC
+ h256 mac(o["mac"].get_str());
+ (void)mac;
+
+ bytes cipherText = fromHex(o["ciphertext"].get_str());
+ bytes ret;
+ if (o["cipher"].get_str() == "aes-128-cbc")
+ {
+ auto params = o["cipherparams"].get_obj();
+ h128 key(sha3(h128(pKey, h128::AlignRight)), h128::AlignRight);
+ h128 iv(params["iv"].get_str());
+ decryptSymNoAuth(key, iv, &cipherText, ret);
+ }
+ else
+ {
+ cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
+ return bytes();
+ }
+
+ return ret;
+ }
+
+ std::map m_keys;
+};
+
+int main()
+{
+ KeyManager keyman;
+ cdebug << "Secret key for 0498f19a-59db-4d54-ac95-33901b4f1870 is " << keyman.secret(fromUUID("0498f19a-59db-4d54-ac95-33901b4f1870"), "foo");
+}
+
+#elif 0
int main()
{
DownloadMan man;
diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp
index 72b5543a8..be8152b55 100644
--- a/libdevcore/Common.cpp
+++ b/libdevcore/Common.cpp
@@ -28,7 +28,7 @@ using namespace dev;
namespace dev
{
-char const* Version = "0.9.14";
+char const* Version = "0.9.15";
void HasInvariants::checkInvariants() const
{
@@ -36,9 +36,19 @@ void HasInvariants::checkInvariants() const
BOOST_THROW_EXCEPTION(FailedInvariant());
}
+struct TimerChannel: public LogChannel { static const char* name(); static const int verbosity = 0; };
+
+#ifdef _WIN32
+const char* TimerChannel::name() { return EthRed " ! "; }
+#else
+const char* TimerChannel::name() { return EthRed " ⚡ "; }
+#endif
+
TimerHelper::~TimerHelper()
{
- cdebug << "Timer" << id << t.elapsed() << "s";
+ auto e = m_t.elapsed();
+ if (!m_ms || e * 1000 > m_ms)
+ clog(TimerChannel) << m_id << e << "s";
}
}
diff --git a/libdevcore/Common.h b/libdevcore/Common.h
index aa18baba5..e0872b5d4 100644
--- a/libdevcore/Common.h
+++ b/libdevcore/Common.h
@@ -169,20 +169,34 @@ private:
#define DEV_INVARIANT_CHECK (void)0;
#endif
+/// Simple scope-based timer helper.
class TimerHelper
{
public:
- TimerHelper(char const* _id): id(_id) {}
+ TimerHelper(char const* _id, unsigned _msReportWhenGreater = 0): m_id(_id), m_ms(_msReportWhenGreater) {}
~TimerHelper();
private:
- boost::timer t;
- char const* id;
+ boost::timer m_t;
+ char const* m_id;
+ unsigned m_ms;
};
#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(#S, true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S)
+#if WIN32
+#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__)
+#else
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__)
+#endif
+
+#define DEV_TIMED_IF(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false)
+#define DEV_TIMED_SCOPE_IF(S) ::dev::TimerHelper __eth_t(S, MS)
+#if WIN32
+#define DEV_TIMED_FUNCTION_IF(MS) DEV_TIMED_SCOPE_IF(__FUNCSIG__, MS)
+#else
+#define DEV_TIMED_FUNCTION_IF(MS) DEV_TIMED_SCOPE_IF(__PRETTY_FUNCTION__, MS)
+#endif
enum class WithExisting: int
{
diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h
index d060108ef..2d3eced32 100644
--- a/libdevcore/Guards.h
+++ b/libdevcore/Guards.h
@@ -81,9 +81,9 @@ using SpinGuard = std::lock_guard;
* Mutex m;
* unsigned d;
* ...
- * ETH_GUARDED(m) d = 1;
+ * ETH_(m) d = 1;
* ...
- * ETH_GUARDED(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; }
+ * ETH_(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; }
* @endcode
*
* There are several variants of this basic mechanism for different Mutex types and Guards.
@@ -95,7 +95,7 @@ using SpinGuard = std::lock_guard;
* Mutex m;
* int d;
* ...
- * ETH_GUARDED(m)
+ * ETH_(m)
* {
* for (auto d = 50; d > 25; --d)
* foo(d);
@@ -107,19 +107,19 @@ using SpinGuard = std::lock_guard;
* @endcode
*/
-#define ETH_GUARDED(MUTEX) \
+#define DEV_GUARDED(MUTEX) \
for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
-#define ETH_READ_GUARDED(MUTEX) \
+#define DEV_READ_GUARDED(MUTEX) \
for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
-#define ETH_WRITE_GUARDED(MUTEX) \
+#define DEV_WRITE_GUARDED(MUTEX) \
for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
-#define ETH_RECURSIVE_GUARDED(MUTEX) \
+#define DEV_RECURSIVE_GUARDED(MUTEX) \
for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
-#define ETH_UNGUARDED(MUTEX) \
+#define DEV_UNGUARDED(MUTEX) \
for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
-#define ETH_READ_UNGUARDED(MUTEX) \
+#define DEV_READ_UNGUARDED(MUTEX) \
for (GenericUnguardSharedBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
-#define ETH_WRITE_UNGUARDED(MUTEX) \
+#define DEV_WRITE_UNGUARDED(MUTEX) \
for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
}
diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp
index a68c18958..7d790ccf6 100644
--- a/libdevcore/Worker.cpp
+++ b/libdevcore/Worker.cpp
@@ -29,7 +29,7 @@ using namespace dev;
void Worker::startWorking()
{
- cnote << "startWorking for thread" << m_name;
+// cnote << "startWorking for thread" << m_name;
Guard l(x_work);
if (m_work)
{
@@ -42,65 +42,66 @@ void Worker::startWorking()
m_work.reset(new thread([&]()
{
setThreadName(m_name.c_str());
- cnote << "Thread begins";
+// cnote << "Thread begins";
while (m_state != WorkerState::Killing)
{
WorkerState ex = WorkerState::Starting;
bool ok = m_state.compare_exchange_strong(ex, WorkerState::Started);
- cnote << "Trying to set Started: Thread was" << (unsigned)ex << "; " << ok;
+// cnote << "Trying to set Started: Thread was" << (unsigned)ex << "; " << ok;
+ (void)ok;
startedWorking();
- cnote << "Entering work loop...";
+// cnote << "Entering work loop...";
workLoop();
- cnote << "Finishing up worker thread...";
+// cnote << "Finishing up worker thread...";
doneWorking();
// ex = WorkerState::Stopping;
// m_state.compare_exchange_strong(ex, WorkerState::Stopped);
ex = m_state.exchange(WorkerState::Stopped);
- cnote << "State: Stopped: Thread was" << (unsigned)ex;
+// cnote << "State: Stopped: Thread was" << (unsigned)ex;
if (ex == WorkerState::Killing || ex == WorkerState::Starting)
m_state.exchange(ex);
- cnote << "Waiting until not Stopped...";
- while (m_state == WorkerState::Stopped)
- this_thread::sleep_for(chrono::milliseconds(20));
+// cnote << "Waiting until not Stopped...";
+ DEV_TIMED_IF(Worker stopping, 100)
+ while (m_state == WorkerState::Stopped)
+ this_thread::sleep_for(chrono::milliseconds(20));
}
}));
- cnote << "Spawning" << m_name;
+// cnote << "Spawning" << m_name;
}
- cnote << "Waiting until Started...";
- while (m_state != WorkerState::Started)
- this_thread::sleep_for(chrono::microseconds(20));
+ DEV_TIMED_IF(Start worker, 100)
+ while (m_state != WorkerState::Started)
+ this_thread::sleep_for(chrono::microseconds(20));
}
void Worker::stopWorking()
{
- cnote << "stopWorking for thread" << m_name;
- ETH_GUARDED(x_work)
+ DEV_GUARDED(x_work)
if (m_work)
{
- cnote << "Stopping" << m_name;
WorkerState ex = WorkerState::Started;
m_state.compare_exchange_strong(ex, WorkerState::Stopping);
- cnote << "Waiting until Stopped...";
- while (m_state != WorkerState::Stopped)
- this_thread::sleep_for(chrono::microseconds(20));
+ DEV_TIMED_IF(Stop worker, 100)
+ while (m_state != WorkerState::Stopped)
+ this_thread::sleep_for(chrono::microseconds(20));
}
}
void Worker::terminate()
{
// cnote << "stopWorking for thread" << m_name;
- ETH_GUARDED(x_work)
+ DEV_GUARDED(x_work)
if (m_work)
{
- cnote << "Terminating" << m_name;
m_state.exchange(WorkerState::Killing);
- m_work->join();
+ DEV_TIMED_IF(Terminate worker, 100)
+ m_work->join();
+
m_work.reset();
}
}
diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp
index ec6a9121b..48dd5c384 100644
--- a/libdevcrypto/Common.cpp
+++ b/libdevcrypto/Common.cpp
@@ -112,13 +112,13 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
return decrypt(_k, _cipher, o_plain);
}
-h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
+h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher)
{
h128 iv(Nonce::get());
return encryptSymNoAuth(_k, _plain, o_cipher, iv);
}
-h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv)
+h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv)
{
o_cipher.resize(_plain.size());
@@ -139,7 +139,7 @@ h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_ciph
}
}
-bool dev::decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext)
+bool dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext)
{
o_plaintext.resize(_cipher.size());
@@ -175,6 +175,14 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
return s_secp256k1.verify(_p, _s, _hash.ref(), true);
}
+h256 dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations)
+{
+ h256 ret;
+ PKCS5_PBKDF2_HMAC pbkdf;
+ pbkdf.DeriveKey(ret.data(), ret.size, 0, (byte*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _iterations);
+ return ret;
+}
+
KeyPair KeyPair::create()
{
static boost::thread_specific_ptr s_eng;
diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h
index 3159f4e7e..50072c1bf 100644
--- a/libdevcrypto/Common.h
+++ b/libdevcrypto/Common.h
@@ -103,13 +103,13 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypts payload with random IV/ctr using AES128-CTR.
-h128 encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher);
+h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Encrypts payload with specified IV/ctr using AES128-CTR.
-h128 encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv);
+h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv);
-/// Decrypts payload with specified IV/ctr.
-bool decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext);
+/// Decrypts payload with specified IV/ctr using AES128-CTR.
+bool decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext);
/// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash);
@@ -120,6 +120,9 @@ Signature sign(Secret const& _k, h256 const& _hash);
/// Verify signature.
bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
+/// Derive key via PBKDF2.
+h256 pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations);
+
/// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).
@@ -164,7 +167,7 @@ struct InvalidState: public dev::Exception {};
/// Key derivation
h256 kdf(Secret const& _priv, h256 const& _hash);
-
+
/**
* @brief Generator for nonce material
*/
diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp
index ff22b9b45..e89857502 100644
--- a/libdevcrypto/CryptoPP.cpp
+++ b/libdevcrypto/CryptoPP.cpp
@@ -79,7 +79,7 @@ void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher)
ctx.Final(mKey.data());
bytes cipherText;
- encryptSymNoAuth(*(Secret*)eKey.data(), bytesConstRef(&io_cipher), cipherText, h128());
+ encryptSymNoAuth(h128(eKey), bytesConstRef(&io_cipher), cipherText, h128());
if (cipherText.empty())
return;
@@ -139,7 +139,7 @@ bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text)
if (mac[i] != msgMac[i])
return false;
- decryptSymNoAuth(*(Secret*)eKey.data(), iv, cipherNoIV, plain);
+ decryptSymNoAuth(h128(eKey), iv, cipherNoIV, plain);
io_text.resize(plain.size());
io_text.swap(plain);
diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp
index 111f92529..42098e09d 100644
--- a/libethash-cl/ethash_cl_miner.cpp
+++ b/libethash-cl/ethash_cl_miner.cpp
@@ -88,6 +88,13 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic
return "{ \"platform\": \"" + platforms[platform_num].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }";
}
+unsigned ethash_cl_miner::get_num_platforms()
+{
+ std::vector platforms;
+ cl::Platform::get(&platforms);
+ return platforms.size();
+}
+
unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
{
std::vector platforms;
@@ -117,14 +124,11 @@ void ethash_cl_miner::finish()
}
}
-bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
+bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
{
- // store params
- m_params = params;
-
// get all platforms
- std::vector platforms;
- cl::Platform::get(&platforms);
+ std::vector platforms;
+ cl::Platform::get(&platforms);
if (platforms.empty())
{
cout << "No OpenCL platforms found." << endl;
@@ -137,10 +141,10 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function().c_str() << endl;
- // get GPU device of the default platform
- std::vector devices;
+ // get GPU device of the default platform
+ std::vector devices;
platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices);
- if (devices.empty())
+ if (devices.empty())
{
cout << "No OpenCL devices found." << endl;
return false;
@@ -171,7 +175,7 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0);
- static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
+ static unsigned get_num_platforms();
static unsigned get_num_devices(unsigned _platformId = 0);
+ static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
-
+ bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0);
void finish();
void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count);
void search(uint8_t const* header, uint64_t target, search_hook& hook);
@@ -43,7 +43,6 @@ public:
private:
enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 };
- ethash_params m_params;
cl::Context m_context;
cl::CommandQueue m_queue;
cl::Kernel m_hash_kernel;
diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp
index e932fced4..011f0b9e0 100644
--- a/libethcore/Ethash.cpp
+++ b/libethcore/Ethash.cpp
@@ -309,10 +309,10 @@ void Ethash::GPUMiner::workLoop()
delete m_miner;
m_miner = new ethash_cl_miner;
- auto p = EthashAux::params(m_minerSeed);
- auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); };
unsigned device = instances() > 1 ? index() : s_deviceId;
- m_miner->init(p, cb, 32, s_platformId, device);
+
+ EthashAux::FullType dag = EthashAux::full(m_minerSeed);
+ m_miner->init(dag->data.data(), dag->data.size(), 32, s_platformId, device);
}
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp
index ad7dfe53b..0b9af98ac 100644
--- a/libethcore/EthashAux.cpp
+++ b/libethcore/EthashAux.cpp
@@ -133,7 +133,6 @@ EthashAux::LightAllocation::~LightAllocation()
ethash_delete_light(light);
}
-
EthashAux::FullType EthashAux::full(BlockInfo const& _header, bytesRef _dest, bool _createIfMissing)
{
return full(_header.seedHash(), _dest, _createIfMissing);
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index 955568c54..192cff34c 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -48,7 +48,7 @@ using namespace dev::eth;
namespace js = json_spirit;
#define ETH_CATCH 1
-#define ETH_TIMED_IMPORTS 1
+#define ETH_TIMED_IMPORTS 0
#ifdef _WIN32
const char* BlockChainDebug::name() { return EthBlue "8" EthWhite " <>"; }
@@ -474,7 +474,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
t.restart();
#endif
-#if ETH_PARANOIA
+#if ETH_PARANOIA || !ETH_TRUE
checkConsistency();
#endif
@@ -486,29 +486,26 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
// This is safe in practice since the caches don't get flushed nearly often enough to be
// done here.
details(bi.parentHash);
- ETH_WRITE_GUARDED(x_details)
+ DEV_WRITE_GUARDED(x_details)
m_details[bi.parentHash].children.push_back(bi.hash());
-#if ETH_TIMED_IMPORTS
+#if ETH_TIMED_IMPORTS || !ETH_TRUE
collation = t.elapsed();
t.restart();
#endif
blocksBatch.Put(toSlice(bi.hash()), (ldb::Slice)ref(_block));
- ETH_READ_GUARDED(x_details)
+ DEV_READ_GUARDED(x_details)
extrasBatch.Put(toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp()));
+
extrasBatch.Put(toSlice(bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}).rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp()));
extrasBatch.Put(toSlice(bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp()));
-#if ETH_TIMED_IMPORTS
+#if ETH_TIMED_IMPORTS || !ETH_TRUE
writing = t.elapsed();
t.restart();
#endif
-
-#if ETH_PARANOIA
- checkConsistency();
-#endif
}
#if ETH_CATCH
catch (InvalidNonce const& _e)
@@ -610,7 +607,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
}
clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << route;
- noteCanonChanged();
StructuredLogger::chainNewHead(
bi.headerHash(WithoutNonce).abridged(),
@@ -627,12 +623,16 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch);
- ETH_WRITE_GUARDED(x_lastBlockHash)
+ DEV_WRITE_GUARDED(x_lastBlockHash)
{
m_lastBlockHash = newLastBlockHash;
m_lastBlockNumber = newLastBlockNumber;
}
+#if ETH_PARANOIA || !ETH_TRUE
+ checkConsistency();
+#endif
+
#if ETH_TIMED_IMPORTS
checkBest = t.elapsed();
cnote << "Import took:" << total.elapsed();
@@ -643,6 +643,9 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
cnote << "checkBest:" << checkBest;
#endif
+ if (!route.empty())
+ noteCanonChanged();
+
if (isKnown(bi.hash()) && !details(bi.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
@@ -978,7 +981,7 @@ bool BlockChain::isKnown(h256 const& _hash) const
if (_hash == m_genesisHash)
return true;
- ETH_READ_GUARDED(x_blocks)
+ DEV_READ_GUARDED(x_blocks)
if (!m_blocks.count(_hash))
{
string d;
@@ -986,7 +989,7 @@ bool BlockChain::isKnown(h256 const& _hash) const
if (d.empty())
return false;
}
- ETH_READ_GUARDED(x_details)
+ DEV_READ_GUARDED(x_details)
if (!m_details.count(_hash))
{
string d;
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index 394b0007e..01426527f 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -244,13 +244,13 @@ void Client::startedWorking()
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
cdebug << "startedWorking()";
- ETH_WRITE_GUARDED(x_preMine)
+ DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc);
- ETH_READ_GUARDED(x_preMine)
+ DEV_READ_GUARDED(x_preMine)
{
- ETH_WRITE_GUARDED(x_working)
+ DEV_WRITE_GUARDED(x_working)
m_working = m_preMine;
- ETH_WRITE_GUARDED(x_postMine)
+ DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_preMine;
}
}
@@ -259,13 +259,13 @@ 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.
- ETH_WRITE_GUARDED(x_preMine)
+ DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc);
- ETH_READ_GUARDED(x_preMine)
+ DEV_READ_GUARDED(x_preMine)
{
- ETH_WRITE_GUARDED(x_working)
+ DEV_WRITE_GUARDED(x_working)
m_working = m_preMine;
- ETH_WRITE_GUARDED(x_postMine)
+ DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_preMine;
}
}
@@ -309,7 +309,7 @@ void Client::killChain()
void Client::clearPending()
{
h256Set changeds;
- ETH_WRITE_GUARDED(x_postMine)
+ DEV_WRITE_GUARDED(x_postMine)
{
if (!m_postMine.pending().size())
return;
@@ -317,7 +317,7 @@ void Client::clearPending()
// appendFromNewPending(m_postMine.logBloom(i), changeds);
changeds.insert(PendingChangedFilter);
m_tq.clear();
- ETH_READ_GUARDED(x_preMine)
+ DEV_READ_GUARDED(x_preMine)
m_postMine = m_preMine;
}
@@ -434,7 +434,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
{
State temp;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
- ETH_READ_GUARDED(x_postMine)
+ DEV_READ_GUARDED(x_postMine)
temp = m_postMine;
temp.addBalance(_from, _value + _gasPrice * _gas);
Executive e(temp, LastHashes(), 0);
@@ -461,13 +461,13 @@ ProofOfWork::WorkPackage Client::getWork()
bool Client::submitWork(ProofOfWork::Solution const& _solution)
{
bytes newBlock;
- DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
+ DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
if (!m_working.completeMine(_solution))
return false;
- ETH_READ_GUARDED(x_working)
+ DEV_READ_GUARDED(x_working)
{
- DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
+ DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
newBlock = m_working.blockData();
}
@@ -499,17 +499,17 @@ void Client::syncTransactionQueue()
h256Set changeds;
TransactionReceipts newPendingReceipts;
- DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
+ DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.empty())
return;
- ETH_READ_GUARDED(x_working)
- DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
+ DEV_READ_GUARDED(x_working)
+ DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
- ETH_READ_GUARDED(x_postMine)
+ DEV_READ_GUARDED(x_postMine)
for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
changeds.insert(PendingChangedFilter);
@@ -561,7 +561,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
bool preChanged = false;
State newPreMine;
- ETH_READ_GUARDED(x_preMine)
+ DEV_READ_GUARDED(x_preMine)
newPreMine = m_preMine;
// TODO: use m_postMine to avoid re-evaluating our own blocks.
@@ -572,11 +572,11 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (isMining())
cnote << "New block on chain.";
- ETH_WRITE_GUARDED(x_preMine)
+ DEV_WRITE_GUARDED(x_preMine)
m_preMine = newPreMine;
- DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
+ DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
m_working = newPreMine;
- ETH_READ_GUARDED(x_postMine)
+ DEV_READ_GUARDED(x_postMine)
for (auto const& t: m_postMine.pending())
{
clog(ClientNote) << "Resubmitting post-mine transaction " << t;
@@ -584,7 +584,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (ir != ImportResult::Success)
onTransactionQueueReady();
}
- ETH_READ_GUARDED(x_working) DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
+ DEV_READ_GUARDED(x_working) DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
changeds.insert(PendingChangedFilter);
@@ -609,11 +609,11 @@ void Client::onPostStateChanged()
cnote << "Post state changed: Restarting mining...";
if (isMining() || remoteActive())
{
- DEV_TIMED(working) ETH_WRITE_GUARDED(x_working)
+ DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc);
- ETH_READ_GUARDED(x_working)
+ DEV_READ_GUARDED(x_working)
{
- DEV_TIMED(post) ETH_WRITE_GUARDED(x_postMine)
+ DEV_TIMED(post) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
m_miningInfo = m_postMine.info();
}
@@ -694,7 +694,7 @@ void Client::checkWatchGarbage()
{
// watches garbage collection
vector toUninstall;
- ETH_GUARDED(x_filtersWatches)
+ DEV_GUARDED(x_filtersWatches)
for (auto key: keysOf(m_watches))
if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20))
{
@@ -733,7 +733,7 @@ eth::State Client::state(h256 _block) const
eth::State Client::state(unsigned _txi) const
{
- ETH_READ_GUARDED(x_postMine)
+ DEV_READ_GUARDED(x_postMine)
return m_postMine.fromPending(_txi);
assert(false);
return State();
diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h
index 2083e9919..0b1469f19 100644
--- a/libethereum/CommonNet.h
+++ b/libethereum/CommonNet.h
@@ -56,7 +56,7 @@ class EthereumPeer;
enum
{
StatusPacket = 0,
- GetTransactionsPacket,
+ NewBlockHashesPacket,
TransactionsPacket,
GetBlockHashesPacket,
BlockHashesPacket,
diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp
index 340ae417f..299984a16 100644
--- a/libethereum/EthereumHost.cpp
+++ b/libethereum/EthereumHost.cpp
@@ -189,7 +189,7 @@ void EthereumHost::maintainTransactions()
for (auto const& i: ts)
{
bool unsent = !m_transactionsSent.count(i.first);
- for (auto const& p: randomSelection(100, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }))
+ for (auto const& p: randomSelection(0, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }).second)
peerTransactions[p].push_back(i.first);
}
for (auto const& t: ts)
@@ -218,28 +218,28 @@ void EthereumHost::maintainTransactions()
}
}
-std::vector> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow)
+pair>, vector>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow)
{
- std::vector> candidates;
- candidates.reserve(peerSessions().size());
+ pair>, vector>> ret;
+ ret.second.reserve(peerSessions().size());
for (auto const& j: peerSessions())
{
auto pp = j.first->cap();
if (_allow(pp.get()))
- candidates.push_back(pp);
+ ret.second.push_back(pp);
}
- std::vector> ret;
- for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && candidates.size();)
+ ret.second.reserve((peerSessions().size() * _percent + 99) / 100);
+ for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && ret.second.size();)
{
- unsigned n = rand() % candidates.size();
- ret.push_back(std::move(candidates[n]));
- candidates.erase(candidates.begin() + n);
+ unsigned n = rand() % ret.second.size();
+ ret.first.push_back(std::move(ret.second[n]));
+ ret.second.erase(ret.second.begin() + n);
}
return ret;
}
-void EthereumHost::maintainBlocks(h256 _currentHash)
+void EthereumHost::maintainBlocks(h256 const& _currentHash)
{
// Send any new blocks.
auto detailsFrom = m_chain.details(m_latestBlockSent);
@@ -253,17 +253,28 @@ void EthereumHost::maintainBlocks(h256 _currentHash)
h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true));
- for (auto const& p: randomSelection(100, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); }))
+ auto s = randomSelection(25, [&](EthereumPeer* p){ DEV_GUARDED(p->x_knownBlocks) return !p->m_knownBlocks.count(_currentHash); return false; });
+ for (shared_ptr const& p: s.first)
for (auto const& b: blocks)
- if (!p->m_knownBlocks.count(b))
- {
- RLPStream ts;
- p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty);
+ {
+ RLPStream ts;
+ p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty);
- Guard l(p->x_knownBlocks);
- p->sealAndSend(ts);
- p->m_knownBlocks.clear();
- }
+ Guard l(p->x_knownBlocks);
+ p->sealAndSend(ts);
+ p->m_knownBlocks.clear();
+ }
+ for (shared_ptr const& p: s.second)
+ {
+ RLPStream ts;
+ p->prep(ts, NewBlockHashesPacket, blocks.size());
+ for (auto const& b: blocks)
+ ts.append(b);
+
+ Guard l(p->x_knownBlocks);
+ p->sealAndSend(ts);
+ p->m_knownBlocks.clear();
+ }
}
m_latestBlockSent = _currentHash;
}
diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h
index c2fffcd82..baa850b5c 100644
--- a/libethereum/EthereumHost.h
+++ b/libethereum/EthereumHost.h
@@ -80,7 +80,7 @@ public:
void noteNewBlocks() { m_newBlocks = true; }
private:
- std::vector> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; });
+ std::pair>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; });
/// Session is tell us that we may need (re-)syncing with the peer.
void noteNeedsSyncing(EthereumPeer* _who);
@@ -92,7 +92,7 @@ private:
void doWork();
void maintainTransactions();
- void maintainBlocks(h256 _currentBlock);
+ void maintainBlocks(h256 const& _currentBlock);
/// Get a bunch of needed blocks.
/// Removes them from our list of needed blocks.
diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp
index 249831540..85bdf33e9 100644
--- a/libethereum/EthereumPeer.cpp
+++ b/libethereum/EthereumPeer.cpp
@@ -326,7 +326,6 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
transition(Asking::Nothing);
break;
}
- case GetTransactionsPacket: break; // DEPRECATED.
case TransactionsPacket:
{
unsigned itemCount = _r.itemCount();
@@ -560,8 +559,51 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
default:;
}
- Guard l(x_knownBlocks);
- m_knownBlocks.insert(h);
+ DEV_GUARDED(x_knownBlocks)
+ m_knownBlocks.insert(h);
+ }
+ break;
+ }
+ case NewBlockHashesPacket:
+ {
+ clog(NetMessageSummary) << "NewBlockHashes";
+ if (host()->isSyncing())
+ clog(NetMessageSummary) << "Ignoring since we're already downloading.";
+ else
+ {
+ unsigned knowns = 0;
+ unsigned unknowns = 0;
+ unsigned itemCount = _r.itemCount();
+ for (unsigned i = 0; i < itemCount; ++i)
+ {
+ addRating(1);
+ auto h = _r[i].toHash();
+ DEV_GUARDED(x_knownBlocks)
+ m_knownBlocks.insert(h);
+ auto status = host()->m_bq.blockStatus(h);
+ if (status == QueueStatus::Importing || status == QueueStatus::Ready || host()->m_chain.isKnown(h))
+ knowns++;
+ else if (status == QueueStatus::Bad)
+ {
+ cwarn << "block hash bad!" << h << ". Bailing...";
+ return true;
+ }
+ else if (status == QueueStatus::Unknown)
+ {
+ unknowns++;
+ m_syncingNeededBlocks.push_back(h);
+ }
+ else
+ knowns++;
+ }
+ clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns";
+ if (unknowns > 0)
+ {
+ host()->m_man.resetToChain(m_syncingNeededBlocks);
+ host()->changeSyncer(this);
+ transition(Asking::Blocks);
+ }
+ return true;
}
break;
}
diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h
index a80d5dadd..75ebab02f 100644
--- a/libethereum/EthereumPeer.h
+++ b/libethereum/EthereumPeer.h
@@ -129,7 +129,7 @@ private:
/// This is built as we ask for hashes. Once no more hashes are given, we present this to the
/// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks.
h256s m_syncingNeededBlocks; ///< The blocks that we should download from this peer.
- h256 m_syncingLastReceivedHash; ///< Hash more recently received from peer.
+ h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer.
h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync.
u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync.
diff --git a/libethereum/Farm.h b/libethereum/Farm.h
index fda9d64c3..9acb375ad 100644
--- a/libethereum/Farm.h
+++ b/libethereum/Farm.h
@@ -127,7 +127,7 @@ public:
*/
void resetMiningProgress()
{
- ETH_READ_GUARDED(x_minerWork)
+ DEV_READ_GUARDED(x_minerWork)
for (auto const& i: m_miners)
i->resetHashCount();
resetTimer();
diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp
new file mode 100644
index 000000000..e5fb0e09a
--- /dev/null
+++ b/libevmasm/GasMeter.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 GasMeter.cpp
+ * @author Christian
+ * @date 2015
+ */
+
+#include "GasMeter.h"
+#include
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+
+GasMeter::GasConsumption& GasMeter::GasConsumption::operator+=(GasConsumption const& _other)
+{
+ isInfinite = isInfinite || _other.isInfinite;
+ if (isInfinite)
+ return *this;
+ bigint v = bigint(value) + _other.value;
+ if (v > std::numeric_limits::max())
+ isInfinite = true;
+ else
+ value = u256(v);
+ return *this;
+}
+
+GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item)
+{
+ switch (_item.type()) {
+ case Push:
+ case PushTag:
+ return runGas(Instruction::PUSH1);
+ case Tag:
+ return runGas(Instruction::JUMPDEST);
+ case Operation:
+ {
+ GasConsumption gas = runGas(_item.instruction());
+ switch (_item.instruction())
+ {
+ case Instruction::SSTORE:
+ // @todo logic can be improved
+ gas += c_sstoreSetGas;
+ break;
+ case Instruction::SLOAD:
+ gas += c_sloadGas;
+ break;
+ case Instruction::MSTORE:
+ case Instruction::MSTORE8:
+ case Instruction::MLOAD:
+ case Instruction::RETURN:
+ case Instruction::SHA3:
+ case Instruction::CALLDATACOPY:
+ case Instruction::CODECOPY:
+ case Instruction::EXTCODECOPY:
+ case Instruction::LOG0:
+ case Instruction::LOG1:
+ case Instruction::LOG2:
+ case Instruction::LOG3:
+ case Instruction::LOG4:
+ case Instruction::CALL:
+ case Instruction::CALLCODE:
+ case Instruction::CREATE:
+ case Instruction::EXP:
+ // @todo logic can be improved
+ gas = GasConsumption::infinite();
+ break;
+ default:
+ break;
+ }
+ return gas;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return GasConsumption::infinite();
+}
+
+GasMeter::GasConsumption GasMeter::runGas(Instruction _instruction)
+{
+ if (_instruction == Instruction::JUMPDEST)
+ return GasConsumption(1);
+
+ int tier = instructionInfo(_instruction).gasPriceTier;
+ return tier == InvalidTier ? GasConsumption::infinite() : c_tierStepGas[tier];
+}
+
+
diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h
new file mode 100644
index 000000000..63dbc1380
--- /dev/null
+++ b/libevmasm/GasMeter.h
@@ -0,0 +1,67 @@
+/*
+ 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 GasMeter.cpp
+ * @author Christian
+ * @date 2015
+ */
+
+#pragma once
+
+#include
+#include
+
+namespace dev
+{
+namespace eth
+{
+
+/**
+ * Class that helps computing the maximum gas consumption for instructions.
+ */
+class GasMeter
+{
+public:
+ struct GasConsumption
+ {
+ GasConsumption(u256 _value = 0, bool _infinite = false): value(_value), isInfinite(_infinite) {}
+ static GasConsumption infinite() { return GasConsumption(0, true); }
+
+ GasConsumption& operator+=(GasConsumption const& _otherS);
+ std::ostream& operator<<(std::ostream& _str) const;
+
+ u256 value;
+ bool isInfinite;
+ };
+
+ /// Returns an upper bound on the gas consumed by the given instruction.
+ GasConsumption estimateMax(AssemblyItem const& _item);
+
+private:
+ static GasConsumption runGas(Instruction _instruction);
+};
+
+inline std::ostream& operator<<(std::ostream& _str, GasMeter::GasConsumption const& _consumption)
+{
+ if (_consumption.isInfinite)
+ return _str << "inf";
+ else
+ return _str << _consumption.value;
+}
+
+
+}
+}
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index 78c1102c1..8ba04b0e7 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -176,7 +176,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
{
// session maybe ingress or egress so m_peers and node table entries may not exist
shared_ptr p;
- ETH_RECURSIVE_GUARDED(x_sessions)
+ DEV_RECURSIVE_GUARDED(x_sessions)
{
if (m_peers.count(_id))
p = m_peers[_id];
@@ -208,7 +208,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
// create session so disconnects are managed
auto ps = make_shared(this, _io, p, PeerSessionInfo({_id, clientVersion, _endpoint.address().to_string(), listenPort, chrono::steady_clock::duration(), _rlp[2].toSet(), 0, map()}));
- if (protocolVersion != dev::p2p::c_protocolVersion)
+ if (protocolVersion < dev::p2p::c_protocolVersion)
{
ps->disconnect(IncompatibleProtocol);
return;
@@ -226,7 +226,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
return;
}
- if (peerCount() > 9 * m_idealPeerCount)
+ if (!peerSlotsAvailable(Ingress))
{
ps->disconnect(TooManyPeers);
return;
@@ -257,7 +257,7 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
if (Node n = m_nodeTable->node(_n))
{
shared_ptr p;
- ETH_RECURSIVE_GUARDED(x_sessions)
+ DEV_RECURSIVE_GUARDED(x_sessions)
{
if (m_peers.count(_n))
{
@@ -271,7 +271,7 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
clog(NetNote) << "p2p.host.peers.events.peerAdded " << _n << p->endpoint;
}
}
- if (peerCount() < m_idealPeerCount)
+ if (peerSlotsAvailable(Egress))
connect(p);
}
}
@@ -412,8 +412,7 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
{
// create or update m_peers entry
shared_ptr p;
- ETH_RECURSIVE_GUARDED(x_sessions)
- {
+ DEV_RECURSIVE_GUARDED(x_sessions)
if (m_peers.count(_n))
{
p = m_peers[_n];
@@ -425,7 +424,6 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
p.reset(new Peer(node));
m_peers[_n] = p;
}
- }
connect(p);
}
else if (m_nodeTable)
@@ -438,6 +436,7 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
t->async_wait([this, _n](boost::system::error_code const& _ec)
{
if (!_ec && m_nodeTable)
+ // FIXME RACE CONDITION (use weak_ptr or mutex).
if (auto n = m_nodeTable->node(_n))
requirePeer(n.id, n.endpoint);
});
@@ -578,7 +577,11 @@ void Host::run(boost::system::error_code const&)
// is always live and to ensure reputation and fallback timers are properly
// updated. // disconnectLatePeers();
- int openSlots = m_idealPeerCount - peerCount();
+ // todo: update peerSlotsAvailable()
+ unsigned pendingCount = 0;
+ DEV_GUARDED(x_pendingNodeConns)
+ pendingCount = m_pendingPeerConns.size();
+ int openSlots = m_idealPeerCount - peerCount() - pendingCount;
if (openSlots > 0)
{
list> toConnect;
@@ -759,7 +762,7 @@ void Host::restoreNetwork(bytesConstRef _b)
// todo: ipv6, bi::address_v6(i[0].toArray()
Node n((NodeId)i[2], NodeIPEndpoint(bi::address_v4(i[0].toArray()), i[1].toInt(), i[1].toInt()));
if (i.itemCount() == 3 && n.endpoint.isAllowed())
- m_nodeTable->addNode(n);
+ m_nodeTable->addNode(n, NodeTable::NodeRelation::Known);
else if (i.itemCount() == 10)
{
n.required = i[3].toInt();
@@ -776,7 +779,7 @@ void Host::restoreNetwork(bytesConstRef _b)
if (p->required)
requirePeer(p->id, n.endpoint);
else
- m_nodeTable->addNode(*p.get());
+ m_nodeTable->addNode(*p.get(), NodeTable::NodeRelation::Known);
}
}
}
diff --git a/libp2p/Host.h b/libp2p/Host.h
index 375481c38..41f4d1e72 100644
--- a/libp2p/Host.h
+++ b/libp2p/Host.h
@@ -135,6 +135,8 @@ public:
// TODO: P2P this should be combined with peers into a HostStat object of some kind; coalesce data, as it's only used for status information.
Peers getPeers() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; }
+ NetworkPreferences const& networkPreferences() const { return m_netPrefs; }
+
void setNetworkPreferences(NetworkPreferences const& _p, bool _dropPeers = false) { m_dropPeers = _dropPeers; auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
/// Start network. @threadsafe
@@ -162,6 +164,8 @@ protected:
void restoreNetwork(bytesConstRef _b);
private:
+ enum PeerSlotRatio { Egress = 2, Ingress = 9 };
+
bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; }
/// Determines and sets m_tcpPublic to publicly advertised address.
@@ -169,6 +173,9 @@ private:
void connect(std::shared_ptr const& _p);
+ /// Returns true if pending and connected peer count is less than maximum
+ bool peerSlotsAvailable(PeerSlotRatio _type) { Guard l(x_pendingNodeConns); return peerCount() + m_pendingPeerConns.size() < _type * m_idealPeerCount; }
+
/// Ping the peers to update the latency information and disconnect peers which have timed out.
void keepAlivePeers();
diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp
index de054a178..847e6a42d 100644
--- a/libp2p/Network.cpp
+++ b/libp2p/Network.cpp
@@ -226,7 +226,7 @@ bi::tcp::endpoint Network::resolveHost(string const& _addr)
boost::system::error_code ec;
// resolve returns an iterator (host can resolve to multiple addresses)
bi::tcp::resolver r(s_resolverIoService);
- auto it = r.resolve({split[0], toString(port)}, ec);
+ auto it = r.resolve({bi::tcp::v4(), split[0], toString(port)}, ec);
if (ec)
clog(NetWarn) << "Error resolving host address..." << LogTag::Url << _addr << ":" << LogTag::Error << ec.message();
else
diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp
index e324b8f86..42f1cad02 100644
--- a/libp2p/NodeTable.cpp
+++ b/libp2p/NodeTable.cpp
@@ -81,8 +81,17 @@ shared_ptr NodeTable::addNode(Public const& _pubk, NodeIPEndpoint con
return addNode(node);
}
-shared_ptr NodeTable::addNode(Node const& _node)
+shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relation)
{
+ if (_relation == Known)
+ {
+ shared_ptr ret(new NodeEntry(m_node, _node.id, _node.endpoint));
+ ret->pending = false;
+ m_nodes[_node.id] = ret;
+ noteActiveNode(_node.id, _node.endpoint);
+ return ret;
+ }
+
// re-enable tcp checks when NAT hosts are handled by discover
// we handle when tcp endpoint is 0 below
if (_node.endpoint.address.to_string() == "0.0.0.0")
diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h
index 07247462f..95028db2b 100644
--- a/libp2p/NodeTable.h
+++ b/libp2p/NodeTable.h
@@ -133,12 +133,14 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this
using EvictionTimeout = std::pair; ///< First NodeId (NodeIdTimePoint) may be evicted and replaced with second NodeId.
public:
+ enum NodeRelation { Unknown = 0, Known };
+
/// Constructor requiring host for I/O, credentials, and IP Address and port to listen on.
NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint);
~NodeTable();
/// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable.
- static unsigned distance(NodeId const& _a, NodeId const& _b) { u512 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; }
+ static unsigned distance(NodeId const& _a, NodeId const& _b) { u256 d = sha3(_a) ^ sha3(_b); unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; }
/// Set event handler for NodeEntryAdded and NodeEntryDropped events.
void setEventHandler(NodeTableEventHandler* _handler) { m_nodeEventHandler.reset(_handler); }
@@ -149,8 +151,8 @@ public:
/// Add node. Node will be pinged and empty shared_ptr is returned if NodeId is uknown.
std::shared_ptr addNode(Public const& _pubk, NodeIPEndpoint const& _ep);
- /// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen.
- std::shared_ptr addNode(Node const& _node);
+ /// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen or NodeId is empty.
+ std::shared_ptr addNode(Node const& _node, NodeRelation _relation = NodeRelation::Unknown);
/// To be called when node table is empty. Runs node discovery with m_node.id as the target in order to populate node-table.
void discover();
@@ -178,7 +180,7 @@ private:
/// Constants for Kademlia, derived from address space.
- static unsigned const s_addressByteSize = sizeof(NodeId); ///< Size of address type in bytes.
+ static unsigned const s_addressByteSize = h256::size; ///< Size of address type in bytes.
static unsigned const s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia].
static unsigned const s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us).
static unsigned const s_maxSteps = boost::static_log2::value; ///< Max iterations of discovery. (discover)
diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp
index 713059d38..0a170f8e1 100644
--- a/libsolidity/ASTPrinter.cpp
+++ b/libsolidity/ASTPrinter.cpp
@@ -30,8 +30,11 @@ namespace dev
namespace solidity
{
-ASTPrinter::ASTPrinter(ASTNode const& _ast, string const& _source):
- m_indentation(0), m_source(_source), m_ast(&_ast)
+ASTPrinter::ASTPrinter(
+ ASTNode const& _ast,
+ string const& _source,
+ StructuralGasEstimator::ASTGasConsumption const& _gasCosts
+): m_indentation(0), m_source(_source), m_ast(&_ast), m_gasCosts(_gasCosts)
{
}
@@ -503,6 +506,8 @@ void ASTPrinter::endVisit(Literal const&)
void ASTPrinter::printSourcePart(ASTNode const& _node)
{
+ if (m_gasCosts.count(&_node))
+ *m_ostream << getIndentation() << " Gas costs: " << m_gasCosts.at(&_node) << endl;
if (!m_source.empty())
{
SourceLocation const& location(_node.getLocation());
diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h
index 9494bf8cb..dabf6470a 100644
--- a/libsolidity/ASTPrinter.h
+++ b/libsolidity/ASTPrinter.h
@@ -24,6 +24,7 @@
#include
#include
+#include
namespace dev
{
@@ -38,7 +39,11 @@ class ASTPrinter: public ASTConstVisitor
public:
/// Create a printer for the given abstract syntax tree. If the source is specified,
/// the corresponding parts of the source are printed with each node.
- ASTPrinter(ASTNode const& _ast, std::string const& _source = std::string());
+ ASTPrinter(
+ ASTNode const& _ast,
+ std::string const& _source = std::string(),
+ StructuralGasEstimator::ASTGasConsumption const& _gasCosts = {}
+ );
/// Output the string representation of the AST to _stream.
void print(std::ostream& _stream);
@@ -128,6 +133,7 @@ private:
int m_indentation;
std::string m_source;
ASTNode const* m_ast;
+ StructuralGasEstimator::ASTGasConsumption m_gasCosts;
std::ostream* m_ostream;
};
diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h
index ec22bd443..fbda50791 100644
--- a/libsolidity/ASTVisitor.h
+++ b/libsolidity/ASTVisitor.h
@@ -23,6 +23,8 @@
#pragma once
#include
+#include
+#include
#include
namespace dev
@@ -218,5 +220,47 @@ protected:
virtual void endVisitNode(ASTNode const&) { }
};
+/**
+ * Utility class that visits the AST in depth-first order and calls a function on each node and each edge.
+ * Child nodes are only visited if the node callback of the parent returns true.
+ * The node callback of a parent is called before any edge or node callback involving the children.
+ * The edge callbacks of all children are called before the edge callback of the parent.
+ * This way, the node callback can be used as an initializing callback and the edge callbacks can be
+ * used to compute a "reduce" function.
+ */
+class ASTReduce: public ASTConstVisitor
+{
+public:
+ /**
+ * Constructs a new ASTReduce object with the given callback functions.
+ * @param _onNode called for each node, before its child edges and nodes, should return true to descend deeper
+ * @param _onEdge called for each edge with (parent, child)
+ */
+ ASTReduce(
+ std::function _onNode,
+ std::function _onEdge
+ ): m_onNode(_onNode), m_onEdge(_onEdge)
+ {
+ }
+
+protected:
+ bool visitNode(ASTNode const& _node) override
+ {
+ m_parents.push_back(&_node);
+ return m_onNode(_node);
+ }
+ void endVisitNode(ASTNode const& _node) override
+ {
+ m_parents.pop_back();
+ if (!m_parents.empty())
+ m_onEdge(*m_parents.back(), _node);
+ }
+
+private:
+ std::vector m_parents;
+ std::function m_onNode;
+ std::function m_onEdge;
+};
+
}
}
diff --git a/libsolidity/StructuralGasEstimator.cpp b/libsolidity/StructuralGasEstimator.cpp
new file mode 100644
index 000000000..ececd7116
--- /dev/null
+++ b/libsolidity/StructuralGasEstimator.cpp
@@ -0,0 +1,110 @@
+/*
+ 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 .
+*/
+/**
+ * @author Christian
+ * @date 2015
+ * Gas consumption estimator working alongside the AST.
+ */
+
+#include "StructuralGasEstimator.h"
+#include