diff --git a/CMakeLists.txt b/CMakeLists.txt
index df67d94f8..86c8c687a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,38 +1,82 @@
# cmake global
-project(ethereum)
cmake_minimum_required(VERSION 2.8.9)
-set(CMAKE_AUTOMOC ON)
-cmake_policy(SET CMP0015 NEW)
+
+project(ethereum)
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+
+######################################################################################################
# user defined, defaults
# Normally, set(...CACHE...) creates cache variables, but does not modify them.
+function(createDefaultCacheConfig)
+ set(HEADLESS OFF CACHE BOOL "Do not compile GUI (AlethZero)")
+ set(LANGUAGES OFF CACHE BOOL "Limit build to Serpent/LLL tools")
+ set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)")
+ set(PARANOIA OFF CACHE BOOL "Additional run-time checks")
+endfunction()
-set(HEADLESS OFF CACHE BOOL "Do not compile GUI (AlethZero)")
-set(LANGUAGES OFF CACHE BOOL "Limit build to Serpent/LLL tools")
-set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)")
-set(PARANOIA OFF CACHE BOOL "Additional run-time checks")
-if (LANGUAGES)
- add_definitions(-DETH_LANGUAGES)
-endif ()
+# propagates CMake configuration options to the compiler
+function(configureProject)
+ if (LANGUAGES)
+ add_definitions(-DETH_LANGUAGES)
+ endif ()
-if (PARANOIA)
- if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
- add_definitions(-DETH_PARANOIA)
- else ()
- message(FATAL_ERROR "Paranoia requires debug.")
+ if (PARANOIA)
+ if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ add_definitions(-DETH_PARANOIA)
+ else ()
+ message(FATAL_ERROR "Paranoia requires debug.")
+ endif ()
endif ()
-endif ()
-if (VMTRACE)
- if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
- add_definitions(-DETH_VMTRACE)
+ if (VMTRACE)
+ if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ add_definitions(-DETH_VMTRACE)
+ else ()
+ message(FATAL_ERROR "VM tracing requires debug.")
+ endif ()
+ endif ()
+endfunction()
+
+
+function(createBuildInfo)
+ # Set build platform; to be written to BuildInfo.h
+ if (CMAKE_COMPILER_IS_MINGW)
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/mingw")
+ elseif (CMAKE_COMPILER_IS_MSYS)
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msys")
+ elseif (CMAKE_COMPILER_IS_GNUCXX)
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/g++")
+ elseif (CMAKE_COMPILER_IS_MSVC)
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msvc")
+ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/clang")
else ()
- message(FATAL_ERROR "VM tracing requires debug.")
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/unknown")
endif ()
-endif ()
-message("LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}")
+ # Generate header file containing useful build information
+ add_custom_target(BuildInfo.h ALL COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BUILD_TYPE} ${ETH_BUILD_PLATFORM})
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+ set(SRC_LIST BuildInfo.h)
+endfunction()
+
+######################################################################################################
+
+
+set(CMAKE_AUTOMOC ON)
+cmake_policy(SET CMP0015 NEW)
+
+
+createDefaultCacheConfig()
+configureProject()
+message("-- LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}")
+
# Default TARGET_PLATFORM to "linux".
set(TARGET_PLATFORM CACHE STRING "linux")
@@ -49,290 +93,28 @@ endif ()
# set(CMAKE_BUILD_TYPE RelWithDebInfo)
# endif()
-# Initialize CXXFLAGS
-set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB")
-set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
-set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
-set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG -DETH_RELEASE")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG")
-
-# Windows
-if ("${TARGET_PLATFORM}" STREQUAL "w64")
- set(CMAKE_SYSTEM_NAME Windows)
-
- set(CMAKE_CXX_LIBRARY_ARCHITECTURE x86_64-w64-mingw32)
- set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
- set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
- set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
- set(CMAKE_AR x86_64-w64-mingw32-ar)
- set(CMAKE_RANLIB x86_64-w64-mingw32-ranlib)
-
- set(CMAKE_EXECUTABLE_SUFFIX .exe)
-
- set(CMAKE_FIND_ROOT_PATH
- /usr/x86_64-w64-mingw32
- )
-
- include_directories(/usr/x86_64-w64-mingw32/include/cryptopp)
-
- set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
- set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
- set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-
- set(CMAKE_INSTALL_PREFIX /usr/x86_64-w64-mingw32)
- set(ETH_BUILD_PLATFORM "windows")
- set(ETH_STATIC 1)
-else ()
- set(ETH_BUILD_PLATFORM ${CMAKE_SYSTEM_NAME})
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
- set(ETH_SHARED 1)
-endif()
-# Set build platform; to be written to BuildInfo.h
-if (CMAKE_COMPILER_IS_MINGW)
- set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/mingw")
-elseif (CMAKE_COMPILER_IS_MSYS)
- set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msys")
-elseif (CMAKE_COMPILER_IS_GNUCXX)
- set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/g++")
-elseif (CMAKE_COMPILER_IS_MSVC)
- set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msvc")
-elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/clang")
-else ()
- set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/unknown")
-endif ()
+include(EthCompilerSettings)
+message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}")
-message("CXXFLAGS: ${CMAKE_CXX_FLAGS}")
#add_definitions("-DETH_BUILD_TYPE=${ETH_BUILD_TYPE}")
#add_definitions("-DETH_BUILD_PLATFORM=${ETH_BUILD_PLATFORM}")
-# C++11 check and activation
-if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
- execute_process(
- COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
- if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
- message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
- endif ()
-elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
-else ()
- message(FATAL_ERROR "Your C++ compiler does not support C++11.")
-endif ()
-
-if("${TARGET_PLATFORM}" STREQUAL "w64")
-# set(MINIUPNPC_LS /usr/x86_64-w64-mingw32/lib/libminiupnpc.a)
- set(LEVELDB_LS leveldb)
- set(CRYPTOPP_LS cryptopp)
- set(CRYPTOPP_ID /usr/x86_64-w64-mingw32/include/cryptopp)
-else()
- # Look for available Crypto++ version and if it is >= 5.6.2
- find_path(ID cryptlib.h
- ../cryptopp/src
- ../../cryptopp/src
- /usr/include/cryptopp
- /usr/include/crypto++
- /usr/local/include/cryptopp
- /usr/local/include/crypto++
- /opt/local/include/cryptopp
- /opt/local/include/crypto++
- )
- find_library(LS NAMES cryptoppeth cryptopp
- ../cryptopp/src/../target/build/release
- ../../cryptopp/src/../target/build/release
- PATHS
- /usr/lib
- /usr/local/lib
- /opt/local/lib
- )
-
- if (ID AND LS)
- message(STATUS "Found Crypto++: ${ID}, ${LS}")
- set(_CRYPTOPP_VERSION_HEADER ${ID}/config.h)
- if(EXISTS ${_CRYPTOPP_VERSION_HEADER})
- file(STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION REGEX "^#define CRYPTOPP_VERSION[ \t]+[0-9]+$")
- string(REGEX REPLACE "^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION ${_CRYPTOPP_VERSION})
- if(${_CRYPTOPP_VERSION} LESS 562)
- message(FATAL_ERROR "Crypto++ version found is smaller than 5.6.2.")
- else()
- set(CRYPTOPP_ID ${ID} CACHE FILEPATH "")
- set(CRYPTOPP_LS ${LS} CACHE FILEPATH "")
- message(STATUS "Crypto++ found and version greater or equal to 5.6.2")
- endif()
- endif()
- else()
- message(STATUS "Crypto++ Not Found: ${CRYPTOPP_ID}, ${CRYPTOPP_LS}")
- endif()
-
- find_path( LEVELDB_ID leveldb/db.h
- /usr/include
- /usr/local/include
- )
- if ( LEVELDB_ID STREQUAL "LEVELDB_ID-NOTFOUND" )
- message(FATAL_ERROR "Failed to find the LevelDB headers")
- else ()
- message(STATUS "Found LevelDB Headers")
-
- # Check for accessory dev libraries leveldb and miniupnpc
- find_library( LEVELDB_LS NAMES leveldb
- PATHS
- /usr/lib
- /usr/local/lib
- /opt/local/lib
- /usr/lib/*/
- )
- if ( LEVELDB_LS STREQUAL "LEVELDB_LS-NOTFOUND" )
- message(FATAL_ERROR "Failed to find the LevelDB Library!")
- else ()
- message(STATUS "Found LevelDB Library: ${LEVELDB_LS}")
- add_definitions(-DETH_LEVELDB)
- endif ()
- endif ()
-
- find_path( PYTHON_ID pyconfig.h
- ${PYTHON_INCLUDE_DIR}
- /usr/include/python2.7
- /usr/local/include/python2.7
- )
- if ( PYTHON_ID STREQUAL "PYTHON_ID-NOTFOUND" )
- message(STATUS "Failed to find the Python-2.7 headers")
- else ()
- message(STATUS "Found Python-2.7 Headers: ${PYTHON_ID}")
-
- # Check for accessory dev libraries leveldb and miniupnpc
- find_library( PYTHON_LS NAMES python2.7
- PATHS
- /usr/lib
- /usr/local/lib
- /opt/local/lib
- /usr/lib/*/
- )
- if ( PYTHON_LS STREQUAL "PYTHON_LS-NOTFOUND" )
- message(STATUS "Failed to find the Python-2.7 Library!")
- set(PYTHON_ID)
- set(PYTHON_LS)
- else ()
- message(STATUS "Found Python-2.7 Library: ${PYTHON_LS}")
- add_definitions(-DETH_PYTHON)
- endif ()
- endif ()
-
- find_path( MINIUPNPC_ID miniupnpc/miniwget.h
- /usr/include
- /usr/local/include
- )
- if ( MINIUPNPC_ID )
- message(STATUS "Found miniupnpc headers")
-
- find_library( MINIUPNPC_LS NAMES miniupnpc
- PATHS
- /usr/lib
- /usr/local/lib
- /opt/local/lib
- /usr/lib/*/
- )
- if ( MINIUPNPC_LS )
- message(STATUS "Found miniupnpc library: ${MINIUPNPC_LS}")
- add_definitions(-DETH_MINIUPNPC)
- else ()
- message(STATUS "Failed to find the miniupnpc library!")
- endif ()
- else ()
- message(STATUS "Failed to find the miniupnpc headers!")
- endif ()
-
- find_path( JSONRPC_ID jsonrpc/rpc.h
- /usr/include
- /usr/local/include
- )
- if ( JSONRPC_ID )
- message(STATUS "Found jsonrpc headers")
- find_library( JSONRPC_LS NAMES jsonrpc
- PATHS
- /usr/lib
- /usr/local/lib
- /opt/local/lib
- /usr/lib/*/
- )
- if ( JSONRPC_LS )
- message(STATUS "Found jsonrpc library: ${JSONRPC_LS}")
- add_definitions(-DETH_JSONRPC)
- else ()
- message(STATUS "Failed to find the jsonrpc library!")
- endif ()
- else ()
- message(STATUS "Failed to find the jsonrpc headers!")
- endif ()
-
- find_path( READLINE_ID readline/readline.h
- /usr/include
- /usr/local/include
- )
- if ( READLINE_ID )
- message(STATUS "Found readline headers")
- find_library( READLINE_LS NAMES readline
- PATHS
- /usr/lib
- /usr/local/lib
- /opt/local/lib
- /usr/lib/*/
- )
- if ( READLINE_LS )
- message(STATUS "Found readline library: ${READLINE_LS}")
- add_definitions(-DETH_READLINE)
- else ()
- message(STATUS "Failed to find the readline library!")
- endif ()
- else ()
- message(STATUS "Failed to find the readline headers!")
- endif ()
-
- if (LANGUAGES)
- find_package(Boost 1.53 REQUIRED COMPONENTS thread date_time)
- else()
- find_package(Boost 1.53 REQUIRED COMPONENTS thread date_time system regex)
- endif()
- set(QTQML 1)
-endif()
+include(EthDependenciesDeprecated)
-if(CRYPTOPP_ID)
- include_directories(${CRYPTOPP_ID})
-endif()
-if(PYTHON_ID)
- include_directories(${PYTHON_ID})
-endif()
-if(MINIUPNPC_ID)
- include_directories(${MINIUPNPC_ID})
-endif()
-if(LEVELDB_ID)
- include_directories(${LEVELDB_ID})
-endif()
-if(READLINE_ID)
- include_directories(${READLINE_ID})
-endif()
-if(JSONRPC_ID)
- include_directories(${JSONRPC_ID})
-endif()
-
-# Generate header file containing useful build information
-add_custom_target(BuildInfo.h ALL COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BUILD_TYPE} ${ETH_BUILD_PLATFORM})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- link_directories(/usr/local/lib)
- include_directories(/usr/local/include)
-endif()
+createBuildInfo()
add_subdirectory(libdevcore)
add_subdirectory(libevmface)
add_subdirectory(liblll)
add_subdirectory(libserpent)
if(NOT APPLE)
-if(PYTHON_LS)
-add_subdirectory(libpyserpent)
-endif()
+ if(PYTHON_LS)
+ add_subdirectory(libpyserpent)
+ endif()
endif()
+
add_subdirectory(lllc)
add_subdirectory(sc)
if(JSONRPC_LS)
@@ -377,8 +159,6 @@ if (NOT LANGUAGES)
endif()
endif()
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-set(SRC_LIST BuildInfo.h)
enable_testing()
add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth)
diff --git a/README.md b/README.md
index 7529fed50..371b82097 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,11 @@
By Gav Wood, 2014.
-Based on a design by Vitalik Buterin.
+[![Build
++Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build
++Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop
-Contributors, builders and testers include Eric Lombrozo (cross-compilation), Tim Hughes (MSVC compilation & Dagger testing), Alex Leverington (Clang & Mac building), Marko Simovic (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 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.
### Building
diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 5e86ee59a..5a6eb6f32 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -1480,6 +1480,40 @@ font-size: 14pt
+
+
+ QDockWidget::DockWidgetFeatureMask
+
+
+ Nodes
+
+
+ 2
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ QFrame::NoFrame
+
+
+
+
+
+
&Quit
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 7d3fe4085..8d69727f8 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -33,7 +33,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -751,10 +750,39 @@ void Main::refreshNetwork()
{
auto ps = web3()->peers();
+
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
ui->peers->clear();
- for (PeerInfo const& i: ps)
- ui->peers->addItem(QString("[%7] %3 ms - %1:%2 - %4 %5 %6").arg(i.host.c_str()).arg(i.port).arg(chrono::duration_cast(i.lastPing).count()).arg(i.clientVersion.c_str()).arg(QString::fromStdString(toString(i.caps))).arg(QString::fromStdString(toString(i.notes))).arg(i.socket));
+ ui->nodes->clear();
+
+ if (web3()->haveNetwork())
+ {
+ map clients;
+ for (PeerInfo const& i: ps)
+ ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6")
+ .arg(QString::fromStdString(i.host))
+ .arg(i.port)
+ .arg(chrono::duration_cast(i.lastPing).count())
+ .arg(clients[i.id] = QString::fromStdString(i.clientVersion))
+ .arg(QString::fromStdString(toString(i.caps)))
+ .arg(QString::fromStdString(toString(i.notes)))
+ .arg(i.socket)
+ .arg(QString::fromStdString(i.id.abridged())));
+
+ auto ns = web3()->nodes();
+ for (p2p::Node const& i: ns)
+ if (!i.dead)
+ ui->nodes->insertItem(clients.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8")
+ .arg(QString::fromStdString(i.id.abridged()))
+ .arg(QString::fromStdString(toString(i.address)))
+ .arg(i.id == web3()->id() ? "self" : clients.count(i.id) ? clients[i.id] : i.secondsSinceLastAttempted() == -1 ? "session-fail" : i.secondsSinceLastAttempted() >= (int)i.fallbackSeconds() ? "retrying..." : "retry-" + QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s")
+ .arg(i.secondsSinceLastAttempted())
+ .arg(i.secondsSinceLastConnected())
+ .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x" : "")
+ .arg(i.rating)
+ .arg((int)i.idOrigin)
+ );
+ }
}
void Main::refreshAll()
@@ -948,7 +976,7 @@ void Main::timerEvent(QTimerEvent*)
if (interval / 100 % 2 == 0)
refreshMining();
- if (interval / 100 % 2 == 0 && m_webThree->ethereum()->isSyncing())
+ if ((interval / 100 % 2 == 0 && m_webThree->ethereum()->isSyncing()) || interval == 1000)
ui->downloadView->update();
if (m_logChanged)
@@ -1712,9 +1740,9 @@ void Main::on_debugStepBack_triggered()
void Main::on_debugStepBackOut_triggered()
{
- if (ui->debugTimeline->value() > 0)
+ if (ui->debugTimeline->value() > 0 && m_history.size() > 0)
{
- auto ls = m_history[ui->debugTimeline->value()].levels.size();
+ auto ls = m_history[min(ui->debugTimeline->value(), m_history.size() - 1)].levels.size();
int l = ui->debugTimeline->value();
for (; l > 0 && m_history[l].levels.size() >= ls; --l) {}
ui->debugTimeline->setValue(l);
diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake
new file mode 100644
index 000000000..6103970c4
--- /dev/null
+++ b/cmake/EthCompilerSettings.cmake
@@ -0,0 +1,59 @@
+# Set necessary compile and link flags
+
+
+# C++11 check and activation
+if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
+ execute_process(
+ COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
+ if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
+ message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
+ endif ()
+elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+else ()
+ message(FATAL_ERROR "Your C++ compiler does not support C++11.")
+endif ()
+
+
+
+# Initialize CXXFLAGS
+set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB")
+set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
+set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG -DETH_RELEASE")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG")
+
+# Windows
+if ("${TARGET_PLATFORM}" STREQUAL "w64")
+ set(CMAKE_SYSTEM_NAME Windows)
+
+ set(CMAKE_CXX_LIBRARY_ARCHITECTURE x86_64-w64-mingw32)
+ set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
+ set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
+ set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
+ set(CMAKE_AR x86_64-w64-mingw32-ar)
+ set(CMAKE_RANLIB x86_64-w64-mingw32-ranlib)
+
+ set(CMAKE_EXECUTABLE_SUFFIX .exe)
+
+ set(CMAKE_FIND_ROOT_PATH
+ /usr/x86_64-w64-mingw32
+ )
+
+ include_directories(/usr/x86_64-w64-mingw32/include/cryptopp)
+
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+ set(CMAKE_INSTALL_PREFIX /usr/x86_64-w64-mingw32)
+ set(ETH_BUILD_PLATFORM "windows")
+ set(ETH_STATIC 1)
+else ()
+ set(ETH_BUILD_PLATFORM ${CMAKE_SYSTEM_NAME})
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+ set(ETH_SHARED 1)
+endif()
+
+
+
diff --git a/cmake/EthDependenciesDeprecated.cmake b/cmake/EthDependenciesDeprecated.cmake
new file mode 100644
index 000000000..d1c51f6c4
--- /dev/null
+++ b/cmake/EthDependenciesDeprecated.cmake
@@ -0,0 +1,208 @@
+# search for and configure dependencies
+
+# deprecated. TODO will rewrite to proper CMake packages
+
+
+
+if("${TARGET_PLATFORM}" STREQUAL "w64")
+# set(MINIUPNPC_LS /usr/x86_64-w64-mingw32/lib/libminiupnpc.a)
+ set(LEVELDB_LS leveldb)
+ set(CRYPTOPP_LS cryptopp)
+ set(CRYPTOPP_ID /usr/x86_64-w64-mingw32/include/cryptopp)
+else()
+ # Look for available Crypto++ version and if it is >= 5.6.2
+ find_path(ID cryptlib.h
+ ../cryptopp/src
+ ../../cryptopp/src
+ /usr/include/cryptopp
+ /usr/include/crypto++
+ /usr/local/include/cryptopp
+ /usr/local/include/crypto++
+ /opt/local/include/cryptopp
+ /opt/local/include/crypto++
+ )
+ find_library(LS NAMES cryptoppeth cryptopp
+ ../cryptopp/src/../target/build/release
+ ../../cryptopp/src/../target/build/release
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ )
+
+ if (ID AND LS)
+ message(STATUS "Found Crypto++: ${ID}, ${LS}")
+ set(_CRYPTOPP_VERSION_HEADER ${ID}/config.h)
+ if(EXISTS ${_CRYPTOPP_VERSION_HEADER})
+ file(STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION REGEX "^#define CRYPTOPP_VERSION[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION ${_CRYPTOPP_VERSION})
+ if(${_CRYPTOPP_VERSION} LESS 562)
+ message(FATAL_ERROR "Crypto++ version found is smaller than 5.6.2.")
+ else()
+ set(CRYPTOPP_ID ${ID} CACHE FILEPATH "")
+ set(CRYPTOPP_LS ${LS} CACHE FILEPATH "")
+ message(STATUS "Crypto++ found and version greater or equal to 5.6.2")
+ endif()
+ endif()
+ else()
+ message(STATUS "Crypto++ Not Found: ${CRYPTOPP_ID}, ${CRYPTOPP_LS}")
+ endif()
+
+ find_path( LEVELDB_ID leveldb/db.h
+ /usr/include
+ /usr/local/include
+ )
+ if ( LEVELDB_ID STREQUAL "LEVELDB_ID-NOTFOUND" )
+ message(FATAL_ERROR "Failed to find the LevelDB headers")
+ else ()
+ message(STATUS "Found LevelDB Headers")
+
+ # Check for accessory dev libraries leveldb and miniupnpc
+ find_library( LEVELDB_LS NAMES leveldb
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ /usr/lib/*/
+ )
+ if ( LEVELDB_LS STREQUAL "LEVELDB_LS-NOTFOUND" )
+ message(FATAL_ERROR "Failed to find the LevelDB Library!")
+ else ()
+ message(STATUS "Found LevelDB Library: ${LEVELDB_LS}")
+ add_definitions(-DETH_LEVELDB)
+ endif ()
+ endif ()
+
+ find_path( PYTHON_ID pyconfig.h
+ ${PYTHON_INCLUDE_DIR}
+ /usr/include/python2.7
+ /usr/local/include/python2.7
+ )
+ if ( PYTHON_ID STREQUAL "PYTHON_ID-NOTFOUND" )
+ message(STATUS "Failed to find the Python-2.7 headers")
+ else ()
+ message(STATUS "Found Python-2.7 Headers: ${PYTHON_ID}")
+
+ # Check for accessory dev libraries leveldb and miniupnpc
+ find_library( PYTHON_LS NAMES python2.7
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ /usr/lib/*/
+ )
+ if ( PYTHON_LS STREQUAL "PYTHON_LS-NOTFOUND" )
+ message(STATUS "Failed to find the Python-2.7 Library!")
+ set(PYTHON_ID)
+ set(PYTHON_LS)
+ else ()
+ message(STATUS "Found Python-2.7 Library: ${PYTHON_LS}")
+ add_definitions(-DETH_PYTHON)
+ endif ()
+ endif ()
+
+ find_path( MINIUPNPC_ID miniupnpc/miniwget.h
+ /usr/include
+ /usr/local/include
+ )
+ if ( MINIUPNPC_ID )
+ message(STATUS "Found miniupnpc headers")
+
+ find_library( MINIUPNPC_LS NAMES miniupnpc
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ /usr/lib/*/
+ )
+ if ( MINIUPNPC_LS )
+ message(STATUS "Found miniupnpc library: ${MINIUPNPC_LS}")
+ add_definitions(-DETH_MINIUPNPC)
+ else ()
+ message(STATUS "Failed to find the miniupnpc library!")
+ endif ()
+ else ()
+ message(STATUS "Failed to find the miniupnpc headers!")
+ endif ()
+
+ find_path( JSONRPC_ID jsonrpc/rpc.h
+ /usr/include
+ /usr/local/include
+ )
+ if ( JSONRPC_ID )
+ message(STATUS "Found jsonrpc headers")
+ find_library( JSONRPC_LS NAMES jsonrpc
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ /usr/lib/*/
+ )
+ if ( JSONRPC_LS )
+ message(STATUS "Found jsonrpc library: ${JSONRPC_LS}")
+ add_definitions(-DETH_JSONRPC)
+ else ()
+ message(STATUS "Failed to find the jsonrpc library!")
+ endif ()
+ else ()
+ message(STATUS "Failed to find the jsonrpc headers!")
+ endif ()
+
+ find_path( READLINE_ID readline/readline.h
+ /usr/include
+ /usr/local/include
+ )
+ if ( READLINE_ID )
+ message(STATUS "Found readline headers")
+ find_library( READLINE_LS NAMES readline
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ /usr/lib/*/
+ )
+ if ( READLINE_LS )
+ message(STATUS "Found readline library: ${READLINE_LS}")
+ add_definitions(-DETH_READLINE)
+ else ()
+ message(STATUS "Failed to find the readline library!")
+ endif ()
+ else ()
+ message(STATUS "Failed to find the readline headers!")
+ endif ()
+
+ if (LANGUAGES)
+ find_package(Boost 1.53 REQUIRED COMPONENTS thread date_time)
+ else()
+ find_package(Boost 1.53 REQUIRED COMPONENTS thread date_time system regex)
+ endif()
+
+ set(QTQML 1)
+endif()
+
+if(CRYPTOPP_ID)
+ include_directories(${CRYPTOPP_ID})
+endif()
+if(PYTHON_ID)
+ include_directories(${PYTHON_ID})
+endif()
+if(MINIUPNPC_ID)
+ include_directories(${MINIUPNPC_ID})
+endif()
+if(LEVELDB_ID)
+ include_directories(${LEVELDB_ID})
+endif()
+if(READLINE_ID)
+ include_directories(${READLINE_ID})
+endif()
+if(JSONRPC_ID)
+ include_directories(${JSONRPC_ID})
+endif()
+
+
+
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ link_directories(/usr/local/lib)
+ include_directories(/usr/local/include)
+endif()
diff --git a/eth/main.cpp b/eth/main.cpp
index 40932d0a4..45acbef1c 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#if ETH_JSONRPC
@@ -166,6 +167,13 @@ string pretty(h160 _a, dev::eth::State _st)
return ns;
}
+bool g_exit = false;
+
+void sighandler(int)
+{
+ g_exit = true;
+}
+
int main(int argc, char** argv)
{
unsigned short listenPort = 30303;
@@ -316,6 +324,9 @@ int main(int argc, char** argv)
c->setAddress(coinbase);
}
+ auto nodesState = contents(dbPath + "/nodeState.rlp");
+ web3.restoreNodes(&nodesState);
+
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
web3.startNetwork();
@@ -334,11 +345,15 @@ int main(int argc, char** argv)
}
#endif
+ signal(SIGABRT, &sighandler);
+ signal(SIGTERM, &sighandler);
+ signal(SIGINT, &sighandler);
+
if (interactive)
{
string logbuf;
string l;
- while (true)
+ while (!g_exit)
{
g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << "Press Enter" << flush; };
cout << logbuf << "Press Enter" << flush;
@@ -615,46 +630,47 @@ int main(int argc, char** argv)
try
{
e.setup(&r);
+
+ OnOpFunc oof;
+ if (format == "pretty")
+ oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM)
+ {
+ dev::eth::VM* vm = (VM*)vvm;
+ dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
+ f << endl << " STACK" << endl;
+ for (auto i: vm->stack())
+ f << (h256)i << endl;
+ f << " MEMORY" << endl << dev::memDump(vm->memory());
+ f << " STORAGE" << endl;
+ for (auto const& i: ext->state().storage(ext->myAddress))
+ f << showbase << hex << i.first << ": " << i.second << endl;
+ f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
+ };
+ else if (format == "standard")
+ oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
+ {
+ dev::eth::VM* vm = (VM*)vvm;
+ dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
+ f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
+ };
+ else if (format == "standard+")
+ oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
+ {
+ dev::eth::VM* vm = (VM*)vvm;
+ dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
+ if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
+ for (auto const& i: ext->state().storage(ext->myAddress))
+ f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
+ f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
+ };
+ e.go(oof);
+ e.finalize(oof);
}
catch(Exception const& _e)
{
+ // TODO: a bit more information here. this is probably quite worrying as the transaction is already in the blockchain.
cwarn << diagnostic_information(_e);
}
-
- OnOpFunc oof;
- if (format == "pretty")
- oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM)
- {
- dev::eth::VM* vm = (VM*)vvm;
- dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
- f << endl << " STACK" << endl;
- for (auto i: vm->stack())
- f << (h256)i << endl;
- f << " MEMORY" << endl << dev::memDump(vm->memory());
- f << " STORAGE" << endl;
- for (auto const& i: ext->state().storage(ext->myAddress))
- f << showbase << hex << i.first << ": " << i.second << endl;
- f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
- };
- else if (format == "standard")
- oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
- {
- dev::eth::VM* vm = (VM*)vvm;
- dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
- f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
- };
- else if (format == "standard+")
- oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
- {
- dev::eth::VM* vm = (VM*)vvm;
- dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
- if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
- for (auto const& i: ext->state().storage(ext->myAddress))
- f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
- f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
- };
- e.go(oof);
- e.finalize(oof);
}
}
else if (c && cmd == "inspect")
@@ -764,7 +780,7 @@ int main(int argc, char** argv)
unsigned n =c->blockChain().details().number;
if (mining)
c->startMining();
- while (true)
+ while (!g_exit)
{
if ( c->isMining() &&c->blockChain().details().number - n == mining)
c->stopMining();
@@ -772,9 +788,10 @@ int main(int argc, char** argv)
}
}
else
- while (true)
+ while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
+ writeFile(dbPath + "/nodeState.rlp", web3.saveNodes());
return 0;
}
diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp
index b67e3e62c..41b75f5ec 100644
--- a/libdevcore/Common.cpp
+++ b/libdevcore/Common.cpp
@@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
-char const* Version = "0.7.2";
+char const* Version = "0.7.3";
}
diff --git a/libdevcrypto/MemoryDB.h b/libdevcrypto/MemoryDB.h
index 59435d3bf..446a947ec 100644
--- a/libdevcrypto/MemoryDB.h
+++ b/libdevcrypto/MemoryDB.h
@@ -32,7 +32,7 @@ namespace dev
namespace eth
{
-struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 12; };
+struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; };
#define dbdebug clog(DBChannel)
diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h
index 16e2684fc..3dd76899a 100644
--- a/libdevcrypto/TrieDB.h
+++ b/libdevcrypto/TrieDB.h
@@ -42,7 +42,7 @@ namespace dev
namespace eth
{
-struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 6; };
+struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 17; };
#define tdebug clog(TrieDBChannel)
struct InvalidTrie: virtual dev::Exception {};
diff --git a/libethcore/All.h b/libethcore/All.h
index 4a6747ff0..7a1ca8f51 100644
--- a/libethcore/All.h
+++ b/libethcore/All.h
@@ -2,7 +2,7 @@
#include "BlockInfo.h"
#include "CommonEth.h"
-#include "Dagger.h"
+#include "ProofOfWork.h"
#include "CryptoHeaders.h"
#include "Exceptions.h"
diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp
index f6d5731b3..536f684f2 100644
--- a/libethcore/BlockInfo.cpp
+++ b/libethcore/BlockInfo.cpp
@@ -24,7 +24,7 @@
#include
#include
#include
-#include "Dagger.h"
+#include "ProofOfWork.h"
#include "Exceptions.h"
#include "BlockInfo.h"
using namespace std;
@@ -99,7 +99,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
}
// check it hashes according to proof of work or that it's the genesis block.
- if (_checkNonce && parentHash && !Dagger::verify(headerHashWithoutNonce(), nonce, difficulty))
+ if (_checkNonce && parentHash && !ProofOfWork::verify(headerHashWithoutNonce(), nonce, difficulty))
BOOST_THROW_EXCEPTION(InvalidBlockNonce(headerHashWithoutNonce(), nonce, difficulty));
if (gasUsed > gasLimit)
diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp
index 1526da1b0..40a86dba4 100644
--- a/libethcore/CommonEth.cpp
+++ b/libethcore/CommonEth.cpp
@@ -34,8 +34,8 @@ namespace dev
namespace eth
{
-const unsigned c_protocolVersion = 34;
-const unsigned c_databaseVersion = 2;
+const unsigned c_protocolVersion = 35;
+const unsigned c_databaseVersion = 3;
static const vector> g_units =
{
diff --git a/libethcore/Dagger.h b/libethcore/Dagger.h
deleted file mode 100644
index c32ef38be..000000000
--- a/libethcore/Dagger.h
+++ /dev/null
@@ -1,84 +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 Dagger.h
- * @author Gav Wood
- * @date 2014
- *
- * Dagger algorithm. Or not.
- */
-
-#pragma once
-
-#include
-#include "CommonEth.h"
-
-#define FAKE_DAGGER 1
-
-namespace dev
-{
-namespace eth
-{
-
-struct MineInfo
-{
- void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; }
- double requirement = 0;
- double best = 1e99;
- unsigned hashes = 0;
- bool completed = false;
-};
-
-#if FAKE_DAGGER
-
-class Dagger
-{
-public:
- static h256 eval(h256 const& _root, h256 const& _nonce) { h256 b[2] = { _root, _nonce }; return sha3(bytesConstRef((byte const*)&b[0], 64)); }
- static bool verify(h256 const& _root, h256 const& _nonce, u256 const& _difficulty) { return (bigint)(u256)eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; }
-
- MineInfo mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
-
- h256 m_last;
-};
-
-#else
-
-/// Functions are not re-entrant. If you want to multi-thread, then use different classes for each thread.
-class Dagger
-{
-public:
- Dagger();
- ~Dagger();
-
- static u256 bound(u256 const& _difficulty);
- static h256 eval(h256 const& _root, u256 const& _nonce);
- static bool verify(h256 const& _root, u256 const& _nonce, u256 const& _difficulty);
-
- bool mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool const& _continue = bool(true));
-
-private:
-
- static h256 node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i);
-
- h256 m_root;
- u256 m_nonce;
-};
-
-#endif
-
-}
-}
diff --git a/libethcore/Dagger.cpp b/libethcore/ProofOfWork.cpp
similarity index 50%
rename from libethcore/Dagger.cpp
rename to libethcore/ProofOfWork.cpp
index 956557b64..7d3916fd3 100644
--- a/libethcore/Dagger.cpp
+++ b/libethcore/ProofOfWork.cpp
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see .
*/
-/** @file Dagger.cpp
+/** @file ProofOfWork.cpp
* @author Gav Wood
* @date 2014
*/
@@ -28,7 +28,7 @@
#include
#include
#include
-#include "Dagger.h"
+#include "ProofOfWork.h"
using namespace std;
using namespace std::chrono;
@@ -37,88 +37,8 @@ namespace dev
namespace eth
{
-#if FAKE_DAGGER
-
-MineInfo Dagger::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
-{
- MineInfo ret;
- static std::mt19937_64 s_eng((time(0) + (unsigned)m_last));
- u256 s = (m_last = h256::random(s_eng));
-
- bigint d = (bigint(1) << 256) / _difficulty;
- ret.requirement = log2((double)d);
-
- // 2^ 0 32 64 128 256
- // [--------*-------------------------]
- //
- // evaluate until we run out of time
- auto startTime = steady_clock::now();
- if (!_turbo)
- this_thread::sleep_for(chrono::milliseconds(_msTimeout * 90 / 100));
- for (; (steady_clock::now() - startTime) < milliseconds(_msTimeout) && _continue; s++, ret.hashes++)
- {
- o_solution = (h256)s;
- auto e = (bigint)(u256)eval(_root, o_solution);
- ret.best = min(ret.best, log2((double)e));
- if (e <= d)
- {
- ret.completed = true;
- break;
- }
- }
-
- if (ret.completed)
- assert(verify(_root, o_solution, _difficulty));
-
- return ret;
-}
-
-#else
-
-Dagger::Dagger()
-{
-}
-
-Dagger::~Dagger()
-{
-}
-
-u256 Dagger::bound(u256 const& _difficulty)
-{
- return (u256)((bigint(1) << 256) / _difficulty);
-}
-
-bool Dagger::verify(h256 const& _root, u256 const& _nonce, u256 const& _difficulty)
-{
- return eval(_root, _nonce) < bound(_difficulty);
-}
-
-bool Dagger::mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool const& _continue)
-{
- // restart search if root has changed
- if (m_root != _root)
- {
- m_root = _root;
- m_nonce = 0;
- }
-
- // compute bound
- u256 const b = bound(_difficulty);
-
- // evaluate until we run out of time
- for (auto startTime = steady_clock::now(); (steady_clock::now() - startTime) < milliseconds(_msTimeout) && _continue; m_nonce += 1)
- {
- if (eval(_root, m_nonce) < b)
- {
- o_solution = m_nonce;
- return true;
- }
- }
- return false;
-}
-
template
-inline void update(_T& _sha, u256 const& _value)
+static inline void update(_T& _sha, u256 const& _value)
{
int i = 0;
for (u256 v = _value; v; ++i, v >>= 8) {}
@@ -129,7 +49,7 @@ inline void update(_T& _sha, u256 const& _value)
}
template
-inline void update(_T& _sha, h256 const& _value)
+static inline void update(_T& _sha, h256 const& _value)
{
int i = 0;
byte const* data = _value.data();
@@ -138,14 +58,14 @@ inline void update(_T& _sha, h256 const& _value)
}
template
-inline h256 get(_T& _sha)
+static inline h256 get(_T& _sha)
{
h256 ret;
_sha.TruncatedFinal(&ret[0], 32);
return ret;
}
-h256 Dagger::node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i)
+h256 DaggerEvaluator::node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i)
{
if (_L == _i)
return _root;
@@ -166,9 +86,9 @@ h256 Dagger::node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fas
return get(bsha);
}
-h256 Dagger::eval(h256 const& _root, u256 const& _nonce)
+h256 DaggerEvaluator::eval(h256 const& _root, h256 const& _nonce)
{
- h256 extranonce = _nonce >> 26; // with xn = floor(n / 2^26) -> assuming this is with xn = floor(N / 2^26)
+ h256 extranonce = (u256)_nonce >> 26; // with xn = floor(n / 2^26) -> assuming this is with xn = floor(N / 2^26)
CryptoPP::SHA3_256 bsha;
for (uint_fast32_t k = 0; k < 4; ++k)
{
@@ -185,7 +105,6 @@ h256 Dagger::eval(h256 const& _root, u256 const& _nonce)
return get(bsha);
}
-#endif
}
}
#endif
diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h
new file mode 100644
index 000000000..d942d06f7
--- /dev/null
+++ b/libethcore/ProofOfWork.h
@@ -0,0 +1,117 @@
+/*
+ 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
+ *
+ * ProofOfWork algorithm. Or not.
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include "CommonEth.h"
+
+#define FAKE_DAGGER 1
+
+namespace dev
+{
+namespace eth
+{
+
+struct MineInfo
+{
+ void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; }
+ double requirement = 0;
+ double best = 1e99;
+ unsigned hashes = 0;
+ bool completed = false;
+};
+
+template
+class ProofOfWorkEngine: public Evaluator
+{
+public:
+ static bool verify(h256 const& _root, h256 const& _nonce, u256 const& _difficulty) { return (bigint)(u256)Evaluator::eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; }
+
+ inline MineInfo mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
+
+protected:
+ h256 m_last;
+};
+
+class SHA3Evaluator
+{
+public:
+ static h256 eval(h256 const& _root, h256 const& _nonce) { h256 b[2] = { _root, _nonce }; return sha3(bytesConstRef((byte const*)&b[0], 64)); }
+};
+
+// TODO: class ARPoWEvaluator
+
+class DaggerEvaluator
+{
+public:
+ static h256 eval(h256 const& _root, h256 const& _nonce);
+
+private:
+ static h256 node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i);
+};
+
+using SHA3ProofOfWork = ProofOfWorkEngine;
+
+using ProofOfWork = SHA3ProofOfWork;
+
+template
+MineInfo ProofOfWorkEngine::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
+{
+ MineInfo ret;
+ static std::mt19937_64 s_eng((time(0) + (unsigned)m_last));
+ u256 s = (m_last = h256::random(s_eng));
+
+ bigint d = (bigint(1) << 256) / _difficulty;
+ ret.requirement = log2((double)d);
+
+ // 2^ 0 32 64 128 256
+ // [--------*-------------------------]
+ //
+ // evaluate until we run out of time
+ auto startTime = std::chrono::steady_clock::now();
+ if (!_turbo)
+ std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100));
+ for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, ret.hashes++)
+ {
+ o_solution = (h256)s;
+ auto e = (bigint)(u256)Evaluator::eval(_root, o_solution);
+ ret.best = std::min(ret.best, log2((double)e));
+ if (e <= d)
+ {
+ ret.completed = true;
+ break;
+ }
+ }
+
+ if (ret.completed)
+ assert(verify(_root, o_solution, _difficulty));
+
+ return ret;
+}
+
+}
+}
diff --git a/libethcore/_libethcore.cpp b/libethcore/_libethcore.cpp
index 477034b9e..93eaf0d16 100644
--- a/libethcore/_libethcore.cpp
+++ b/libethcore/_libethcore.cpp
@@ -2,6 +2,6 @@
#include "All.h"
#include "BlockInfo.cpp"
#include "CommonEth.cpp"
-#include "Dagger.cpp"
+#include "ProofOfWork.cpp"
#include "Exceptions.cpp"
#endif
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index dd9f87909..2f0f7040f 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -26,7 +26,7 @@
#include
#include
#include
-#include
+#include
#include
#include "State.h"
#include "Defaults.h"
@@ -429,7 +429,10 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo
void BlockChain::checkConsistency()
{
- m_details.clear();
+ {
+ WriteGuard l(x_details);
+ m_details.clear();
+ }
ldb::Iterator* it = m_db->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().size() == 32)
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index d22f7d873..717e2684c 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -323,23 +323,30 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _
bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
- State temp;
- Transaction t;
-// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
+ bytes out;
+ try
{
- ReadGuard l(x_stateDB);
- temp = m_postMine;
- t.nonce = temp.transactionsFrom(toAddress(_secret));
+ State temp;
+ Transaction t;
+ // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
+ {
+ ReadGuard l(x_stateDB);
+ temp = m_postMine;
+ t.nonce = temp.transactionsFrom(toAddress(_secret));
+ }
+ t.value = _value;
+ t.gasPrice = _gasPrice;
+ t.gas = _gas;
+ t.receiveAddress = _dest;
+ t.data = _data;
+ t.sign(_secret);
+ u256 gasUsed = temp.execute(t.data, &out, false);
+ (void)gasUsed; // TODO: do something with gasused which it returns.
+ }
+ catch (...)
+ {
+ // TODO: Some sort of notification of failure.
}
- t.value = _value;
- t.gasPrice = _gasPrice;
- t.gas = _gas;
- t.receiveAddress = _dest;
- t.data = _data;
- t.sign(_secret);
- bytes out;
- u256 gasUsed = temp.execute(t.data, &out, false);
- (void)gasUsed; // TODO: do something with gasused which it returns.
return out;
}
diff --git a/libethereum/Client.h b/libethereum/Client.h
index e7bbc1ca3..8ec65c199 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -31,7 +31,6 @@
#include
#include
#include
-#include
#include
#include "BlockChain.h"
#include "TransactionQueue.h"
diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp
index 8e92fa9e6..ee5105cd6 100644
--- a/libethereum/EthereumHost.cpp
+++ b/libethereum/EthereumHost.cpp
@@ -189,20 +189,14 @@ void EthereumHost::maintainBlocks(h256 _currentHash)
// If we've finished our initial sync send any new blocks.
if (!isSyncing() && m_chain.isKnown(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty)
{
- // TODO: clean up
- h256s hs;
- hs.push_back(_currentHash);
- bytes bs;
- for (auto h: hs)
- bs += m_chain.block(h);
- clog(NetMessageSummary) << "Sending" << hs.size() << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
+ clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
for (auto j: peers())
{
auto p = j->cap();
RLPStream ts;
- p->prep(ts, NewBlockPacket, hs.size()).appendRaw(bs, hs.size());
+ p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(), 1).append(m_chain.details().totalDifficulty);
Guard l(p->x_knownBlocks);
if (!p->m_knownBlocks.count(_currentHash))
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 105df0172..8f2794c12 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -28,7 +28,6 @@
#include
#include
#include
-#include
#include
#include "BlockChain.h"
#include "Defaults.h"
@@ -837,7 +836,7 @@ MineInfo State::mine(unsigned _msTimeout, bool _turbo)
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
// TODO: Miner class that keeps dagger between mine calls (or just non-polling mining).
- auto ret = m_dagger.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout, true, _turbo);
+ auto ret = m_pow.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout, true, _turbo);
if (!ret.completed)
m_currentBytes.clear();
@@ -1054,14 +1053,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
Manifest ms;
Executive e(*this, &ms);
- try
- {
- e.setup(_rlp);
- }
- catch (Exception const & _e)
- {
- cwarn << diagnostic_information(_e);
- }
+ e.setup(_rlp);
u256 startGasUsed = gasUsed();
diff --git a/libethereum/State.h b/libethereum/State.h
index c73fc95dc..6914b9f5e 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -29,7 +29,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include "TransactionQueue.h"
@@ -322,7 +322,7 @@ private:
Address m_ourAddress; ///< Our address (i.e. the address to which fees go).
- Dagger m_dagger;
+ ProofOfWork m_pow;
u256 m_blockReward;
diff --git a/libevm/VM.h b/libevm/VM.h
index 456e949c7..401e30baf 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -188,8 +188,116 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
}
- default:
+ case Instruction::ADD:
+ case Instruction::MUL:
+ case Instruction::SUB:
+ case Instruction::DIV:
+ case Instruction::SDIV:
+ case Instruction::MOD:
+ case Instruction::SMOD:
+ case Instruction::EXP:
+ case Instruction::NEG:
+ case Instruction::LT:
+ case Instruction::GT:
+ case Instruction::SLT:
+ case Instruction::SGT:
+ case Instruction::EQ:
+ case Instruction::NOT:
+ case Instruction::AND:
+ case Instruction::OR:
+ case Instruction::XOR:
+ case Instruction::BYTE:
+ case Instruction::ADDMOD:
+ case Instruction::MULMOD:
+ case Instruction::ADDRESS:
+ case Instruction::ORIGIN:
+ case Instruction::CALLER:
+ case Instruction::CALLVALUE:
+ case Instruction::CALLDATALOAD:
+ case Instruction::CALLDATASIZE:
+ case Instruction::CODESIZE:
+ case Instruction::EXTCODESIZE:
+ case Instruction::GASPRICE:
+ case Instruction::PREVHASH:
+ case Instruction::COINBASE:
+ case Instruction::TIMESTAMP:
+ case Instruction::NUMBER:
+ case Instruction::DIFFICULTY:
+ case Instruction::GASLIMIT:
+ case Instruction::PUSH1:
+ case Instruction::PUSH2:
+ case Instruction::PUSH3:
+ case Instruction::PUSH4:
+ case Instruction::PUSH5:
+ case Instruction::PUSH6:
+ case Instruction::PUSH7:
+ case Instruction::PUSH8:
+ case Instruction::PUSH9:
+ case Instruction::PUSH10:
+ case Instruction::PUSH11:
+ case Instruction::PUSH12:
+ case Instruction::PUSH13:
+ case Instruction::PUSH14:
+ case Instruction::PUSH15:
+ case Instruction::PUSH16:
+ case Instruction::PUSH17:
+ case Instruction::PUSH18:
+ case Instruction::PUSH19:
+ case Instruction::PUSH20:
+ case Instruction::PUSH21:
+ case Instruction::PUSH22:
+ case Instruction::PUSH23:
+ case Instruction::PUSH24:
+ case Instruction::PUSH25:
+ case Instruction::PUSH26:
+ case Instruction::PUSH27:
+ case Instruction::PUSH28:
+ case Instruction::PUSH29:
+ case Instruction::PUSH30:
+ case Instruction::PUSH31:
+ case Instruction::PUSH32:
+ case Instruction::POP:
+ case Instruction::DUP1:
+ case Instruction::DUP2:
+ case Instruction::DUP3:
+ case Instruction::DUP4:
+ case Instruction::DUP5:
+ case Instruction::DUP6:
+ case Instruction::DUP7:
+ case Instruction::DUP8:
+ case Instruction::DUP9:
+ case Instruction::DUP10:
+ case Instruction::DUP11:
+ case Instruction::DUP12:
+ case Instruction::DUP13:
+ case Instruction::DUP14:
+ case Instruction::DUP15:
+ case Instruction::DUP16:
+ case Instruction::SWAP1:
+ case Instruction::SWAP2:
+ case Instruction::SWAP3:
+ case Instruction::SWAP4:
+ case Instruction::SWAP5:
+ case Instruction::SWAP6:
+ case Instruction::SWAP7:
+ case Instruction::SWAP8:
+ case Instruction::SWAP9:
+ case Instruction::SWAP10:
+ case Instruction::SWAP11:
+ case Instruction::SWAP12:
+ case Instruction::SWAP13:
+ case Instruction::SWAP14:
+ case Instruction::SWAP15:
+ case Instruction::SWAP16:
+ case Instruction::JUMP:
+ case Instruction::JUMPI:
+ case Instruction::PC:
+ case Instruction::MSIZE:
+ case Instruction::GAS:
+ case Instruction::JUMPDEST:
break;
+ default:
+ BOOST_THROW_EXCEPTION(BadInstruction());
}
newTempSize = (newTempSize + 31) / 32 * 32;
@@ -669,8 +777,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
}
case Instruction::STOP:
return bytesConstRef();
- default:
- BOOST_THROW_EXCEPTION(BadInstruction());
}
}
if (_steps == (uint64_t)-1)
diff --git a/libp2p/Capability.cpp b/libp2p/Capability.cpp
index 2dbfd76a8..dfa1ab546 100644
--- a/libp2p/Capability.cpp
+++ b/libp2p/Capability.cpp
@@ -53,14 +53,14 @@ void Capability::sealAndSend(RLPStream& _s)
m_session->sealAndSend(_s);
}
-void Capability::sendDestroy(bytes& _msg)
+void Capability::send(bytesConstRef _msg)
{
- m_session->sendDestroy(_msg);
+ m_session->send(_msg);
}
-void Capability::send(bytesConstRef _msg)
+void Capability::send(bytes&& _msg)
{
- m_session->send(_msg);
+ m_session->send(move(_msg));
}
void Capability::addRating(unsigned _r)
diff --git a/libp2p/Capability.h b/libp2p/Capability.h
index bd2ab7a95..04b116aa8 100644
--- a/libp2p/Capability.h
+++ b/libp2p/Capability.h
@@ -52,7 +52,7 @@ protected:
RLPStream& prep(RLPStream& _s, unsigned _id, unsigned _args = 0);
void sealAndSend(RLPStream& _s);
- void sendDestroy(bytes& _msg);
+ void send(bytes&& _msg);
void send(bytesConstRef _msg);
void addRating(unsigned _r);
diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp
index 540f285c1..8a3b27ef0 100644
--- a/libp2p/Common.cpp
+++ b/libp2p/Common.cpp
@@ -64,7 +64,12 @@ std::string p2p::reasonOf(DisconnectReason _r)
case TooManyPeers: return "Peer had too many connections.";
case DuplicatePeer: return "Peer was already connected.";
case IncompatibleProtocol: return "Peer protocol versions are incompatible.";
+ case NullIdentity: return "Null identity given.";
case ClientQuit: return "Peer is exiting.";
+ case UnexpectedIdentity: return "Unexpected identity given.";
+ case LocalIdentity: return "Connected to ourselves.";
+ case UserReason: return "Subprotocol reason.";
+ case NoDisconnect: return "(No disconnect has happened.)";
default: return "Unknown reason.";
}
}
diff --git a/libp2p/Common.h b/libp2p/Common.h
index 7ef25ca6e..7c2c61156 100644
--- a/libp2p/Common.h
+++ b/libp2p/Common.h
@@ -87,9 +87,27 @@ enum DisconnectReason
NullIdentity,
ClientQuit,
UnexpectedIdentity,
- UserReason = 0x10
+ LocalIdentity,
+ PingTimeout,
+ UserReason = 0x10,
+ NoDisconnect = 0xffff
};
+inline bool isPermanentProblem(DisconnectReason _r)
+{
+ switch (_r)
+ {
+ case DuplicatePeer:
+ case IncompatibleProtocol:
+ case NullIdentity:
+ case UnexpectedIdentity:
+ case LocalIdentity:
+ return true;
+ default:
+ return false;
+ }
+}
+
/// @returns the string form of the given disconnection reason.
std::string reasonOf(DisconnectReason _r);
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index bb9901428..ea89b5613 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -66,7 +66,6 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
m_key(KeyPair::create())
{
populateAddresses();
- m_lastPeersRequest = chrono::steady_clock::time_point::min();
clog(NetNote) << "Id:" << id().abridged();
if (_start)
start();
@@ -112,7 +111,6 @@ void Host::start()
if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
noteNode(id(), m_public, Origin::Perfect, false);
- m_lastPeersRequest = chrono::steady_clock::time_point::min();
clog(NetNote) << "Id:" << id().abridged();
for (auto const& h: m_capabilities)
@@ -144,7 +142,7 @@ void Host::stop()
unsigned Host::protocolVersion() const
{
- return 1;
+ return 2;
}
void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps)
@@ -345,31 +343,46 @@ void Host::populateAddresses()
#endif
}
-shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId)
+shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId)
{
RecursiveGuard l(x_peers);
+ if (_a.port() < 30300 && _a.port() > 30303)
+ cwarn << "Wierd port being recorded!";
+
+ if (_a.port() >= 49152)
+ {
+ cwarn << "Private port being recorded - setting to 0";
+ _a = bi::tcp::endpoint(_a.address(), 0);
+ }
+
cnote << "Node:" << _id.abridged() << _a << (_ready ? "ready" : "used") << _oldId.abridged() << (m_nodes.count(_id) ? "[have]" : "[NEW]");
+
+ // First check for another node with the same connection credentials, and put it in oldId if found.
+ if (!_oldId)
+ for (pair> const& n: m_nodes)
+ if (n.second->address == _a && n.second->id != _id)
+ {
+ _oldId = n.second->id;
+ break;
+ }
+
unsigned i;
if (!m_nodes.count(_id))
{
- shared_ptr old;
if (m_nodes.count(_oldId))
{
- old = m_nodes[_oldId];
- i = old->index;
+ i = m_nodes[_oldId]->index;
m_nodes.erase(_oldId);
m_nodesList[i] = _id;
- m_nodes[id()] = make_shared();
}
else
{
i = m_nodesList.size();
m_nodesList.push_back(_id);
- m_nodes[_id] = make_shared();
}
- m_nodes[_id]->address = m_public;
- m_nodes[_id]->index = i;
+ m_nodes[_id] = make_shared();
m_nodes[_id]->id = _id;
+ m_nodes[_id]->index = i;
m_nodes[_id]->idOrigin = _o;
}
else
@@ -377,6 +390,7 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin
i = m_nodes[_id]->index;
m_nodes[_id]->idOrigin = max(m_nodes[_id]->idOrigin, _o);
}
+ m_nodes[_id]->address = _a;
m_ready.extendAll(i);
m_private.extendAll(i);
if (_ready)
@@ -390,6 +404,8 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin
cnote << m_nodes[_id]->index << ":" << m_ready;
+ m_hadNewNodes = true;
+
return m_nodes[_id];
}
@@ -398,7 +414,8 @@ Nodes Host::potentialPeers(RangeMask const& _known)
RecursiveGuard l(x_peers);
Nodes ret;
- for (auto i: m_ready - (m_private + _known))
+ auto ns = (m_netPrefs.localNetworking ? _known : (m_private + _known)).inverted();
+ for (auto i: ns)
ret.push_back(*m_nodes[m_nodesList[i]]);
return ret;
}
@@ -494,7 +511,9 @@ void Host::connect(bi::tcp::endpoint const& _ep)
void Node::connect(Host* _h)
{
- clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address;
+ clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address << "from" << _h->id().abridged();
+ lastAttempted = std::chrono::system_clock::now();
+ failedAttempts++;
_h->m_ready -= index;
bi::tcp::socket* s = new bi::tcp::socket(_h->m_ioService);
s->async_connect(address, [=](boost::system::error_code const& ec)
@@ -502,14 +521,13 @@ void Node::connect(Host* _h)
if (ec)
{
clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")";
- failedAttempts++;
+ lastDisconnect = TCPError;
lastAttempted = std::chrono::system_clock::now();
_h->m_ready += index;
}
else
{
clog(NetConnect) << "Connected to" << id.abridged() << "@" << address;
- failedAttempts = 0;
lastConnected = std::chrono::system_clock::now();
auto p = make_shared(_h, std::move(*s), _h->node(id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism.
p->start();
@@ -532,14 +550,31 @@ bool Host::havePeer(NodeId _id) const
return !!m_peers.count(_id);
}
-unsigned cumulativeFallback(unsigned _failed)
+unsigned Node::fallbackSeconds() const
{
- if (_failed < 5)
- return _failed * 5;
- else if (_failed < 15)
- return 25 + (_failed - 5) * 10;
- else
- return 25 + 100 + (_failed - 15) * 20;
+ switch (lastDisconnect)
+ {
+ case BadProtocol:
+ return 30 * (failedAttempts + 1);
+ case UselessPeer:
+ case TooManyPeers:
+ case ClientQuit:
+ return 15 * (failedAttempts + 1);
+ case NoDisconnect:
+ return 0;
+ default:
+ if (failedAttempts < 5)
+ return failedAttempts * 5;
+ else if (failedAttempts < 15)
+ return 25 + (failedAttempts - 5) * 10;
+ else
+ return 25 + 100 + (failedAttempts - 15) * 20;
+ }
+}
+
+bool Node::shouldReconnect() const
+{
+ return chrono::system_clock::now() > lastAttempted + chrono::seconds(fallbackSeconds());
}
void Host::growPeers()
@@ -553,7 +588,7 @@ void Host::growPeers()
toTry -= m_private;
set ns;
for (auto i: toTry)
- if (chrono::system_clock::now() > m_nodes[m_nodesList[i]]->lastAttempted + chrono::seconds(cumulativeFallback(m_nodes[m_nodesList[i]]->failedAttempts)))
+ if (m_nodes[m_nodesList[i]]->shouldReconnect())
ns.insert(*m_nodes[m_nodesList[i]]);
if (ns.size())
@@ -566,25 +601,13 @@ void Host::growPeers()
else
{
ensureAccepting();
- if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
- requestPeers();
+ for (auto const& i: m_peers)
+ if (auto p = i.second.lock())
+ p->ensureNodesRequested();
}
}
}
-void Host::requestPeers()
-{
- RLPStream s;
- bytes b;
- Session::prep(s, GetPeersPacket).swapOut(b);
- seal(b);
- for (auto const& i: m_peers)
- if (auto p = i.second.lock())
- if (p->isOpen())
- p->send(&b);
- m_lastPeersRequest = chrono::steady_clock::now();
-}
-
void Host::prunePeers()
{
RecursiveGuard l(x_peers);
@@ -637,6 +660,25 @@ void Host::doWork()
{
growPeers();
prunePeers();
+
+ if (m_hadNewNodes)
+ {
+ for (auto p: m_peers)
+ if (auto pp = p.second.lock())
+ pp->serviceNodesRequest();
+
+ m_hadNewNodes = false;
+ }
+
+ if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s.
+ {
+ for (auto p: m_peers)
+ if (auto pp = p.second.lock())
+ if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60))
+ pp->disconnect(PingTimeout);
+ pingAll();
+ }
+
m_ioService.poll();
}
@@ -646,6 +688,7 @@ void Host::pingAll()
for (auto& i: m_peers)
if (auto j = i.second.lock())
j->ping();
+ m_lastPing = chrono::steady_clock::now();
}
bytes Host::saveNodes() const
@@ -657,7 +700,8 @@ bytes Host::saveNodes() const
for (auto const& i: m_nodes)
{
Node const& n = *(i.second);
- if (n.id != id() && !isPrivateAddress(n.address.address()))
+ // TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 &&
+ if (!n.dead && n.address.port() > 0 && n.address.port() < 49152 && n.id != id() && !isPrivateAddress(n.address.address()))
{
nodes.appendList(10);
if (n.address.address().is_v4())
@@ -667,7 +711,7 @@ bytes Host::saveNodes() const
nodes << n.address.port() << n.id << (int)n.idOrigin
<< std::chrono::duration_cast(n.lastConnected.time_since_epoch()).count()
<< std::chrono::duration_cast(n.lastAttempted.time_since_epoch()).count()
- << n.failedAttempts << n.lastDisconnect << n.score << n.rating;
+ << n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating;
count++;
}
}
@@ -686,7 +730,11 @@ void Host::restoreNodes(bytesConstRef _b)
switch (r[0].toInt())
{
case 0:
+ {
+ auto oldId = id();
m_key = KeyPair(r[1].toHash());
+ noteNode(id(), m_public, Origin::Perfect, false, oldId);
+
for (auto i: r[2])
{
bi::tcp::endpoint ep;
@@ -702,11 +750,12 @@ void Host::restoreNodes(bytesConstRef _b)
n->lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt()));
n->lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt()));
n->failedAttempts = i[6].toInt();
- n->lastDisconnect = (int)i[7].toInt();
+ n->lastDisconnect = (DisconnectReason)i[7].toInt();
n->score = (int)i[8].toInt();
n->rating = (int)i[9].toInt();
}
}
+ }
default:;
}
else
diff --git a/libp2p/Host.h b/libp2p/Host.h
index 723cc5cba..c981edc29 100644
--- a/libp2p/Host.h
+++ b/libp2p/Host.h
@@ -64,19 +64,26 @@ struct Node
bi::tcp::endpoint address; ///< As reported from the node itself.
int score = 0; ///< All time cumulative.
int rating = 0; ///< Trending.
+ bool dead = false; ///< If true, we believe this node is permanently dead - forget all about it.
std::chrono::system_clock::time_point lastConnected;
std::chrono::system_clock::time_point lastAttempted;
unsigned failedAttempts = 0;
- int lastDisconnect = -1; ///< Reason for disconnect that happened last.
+ DisconnectReason lastDisconnect = NoDisconnect; ///< Reason for disconnect that happened last.
- Origin idOrigin = Origin::Unknown; ///< Thirdparty
+ Origin idOrigin = Origin::Unknown; ///< How did we get to know this node's id?
- bool offline() const { return lastDisconnect == -1 || lastAttempted > lastConnected; }
+ int secondsSinceLastConnected() const { return lastConnected == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast(std::chrono::system_clock::now() - lastConnected).count(); }
+ int secondsSinceLastAttempted() const { return lastAttempted == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast(std::chrono::system_clock::now() - lastAttempted).count(); }
+
+ unsigned fallbackSeconds() const;
+ bool shouldReconnect() const;
+
+ bool isOffline() const { return lastAttempted > lastConnected; }
bool operator<(Node const& _n) const
{
- if (offline() != _n.offline())
- return offline();
- else if (offline())
+ if (isOffline() != _n.isOffline())
+ return isOffline();
+ else if (isOffline())
if (lastAttempted == _n.lastAttempted)
return failedAttempts < _n.failedAttempts;
else
@@ -114,7 +121,7 @@ class Host: public Worker
{
friend class Session;
friend class HostCapabilityFace;
- friend class Node;
+ friend struct Node;
public:
/// Start server, listening for connections on the given port.
@@ -165,6 +172,8 @@ public:
/// Deserialise the data and populate the set of known peers.
void restoreNodes(bytesConstRef _b);
+ Nodes nodes() const { RecursiveGuard l(x_peers); Nodes ret; for (auto const& i: m_nodes) ret.push_back(*i.second); return ret; }
+
void setNetworkPreferences(NetworkPreferences const& _p) { stop(); m_netPrefs = _p; start(); }
void start();
@@ -191,11 +200,9 @@ private:
/// This won't touch alter the blockchain.
virtual void doWork();
- std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId = h256());
+ std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = h256());
Nodes potentialPeers(RangeMask const& _known);
- void requestPeers();
-
std::string m_clientVersion; ///< Our version string.
NetworkPreferences m_netPrefs; ///< Network settings.
@@ -211,6 +218,8 @@ private:
bi::tcp::endpoint m_public; ///< Our public listening endpoint.
KeyPair m_key; ///< Our unique ID.
+ bool m_hadNewNodes = false;
+
mutable RecursiveMutex x_peers;
/// The nodes to which we are currently connected.
@@ -227,8 +236,6 @@ private:
RangeMask m_ready; ///< Indices into m_nodesList over to which nodes we are not currently connected, connecting or otherwise ignoring.
RangeMask m_private; ///< Indices into m_nodesList over to which nodes are private.
- std::chrono::steady_clock::time_point m_lastPeersRequest; ///< Last time we asked for some peers - don't want to do this too often. TODO: peers should be pushed, not polled.
-
unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to.
// Our addresses.
@@ -238,6 +245,8 @@ private:
// Our capabilities.
std::map> m_capabilities; ///< Each of the capabilities we support.
+ std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
+
bool m_accepting = false;
};
diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp
index 65517c0d1..1ab4ca123 100644
--- a/libp2p/Session.cpp
+++ b/libp2p/Session.cpp
@@ -40,12 +40,11 @@ Session::Session(Host* _s, bi::tcp::socket _socket, bi::tcp::endpoint const& _ma
m_server(_s),
m_socket(std::move(_socket)),
m_node(nullptr),
- m_manualEndpoint(_manual)
+ m_manualEndpoint(_manual) // NOTE: the port on this shouldn't be used if it's zero.
{
- m_disconnect = std::chrono::steady_clock::time_point::max();
- m_connect = std::chrono::steady_clock::now();
+ m_lastReceived = m_connect = std::chrono::steady_clock::now();
- m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), m_manualEndpoint.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()});
+ m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), 0, std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()});
}
Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& _n, bool _force):
@@ -55,15 +54,19 @@ Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const&
m_manualEndpoint(_n->address),
m_force(_force)
{
- m_disconnect = std::chrono::steady_clock::time_point::max();
- m_connect = std::chrono::steady_clock::now();
+ m_lastReceived = m_connect = std::chrono::steady_clock::now();
m_info = PeerInfo({m_node->id, "?", _n->address.address().to_string(), _n->address.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()});
}
Session::~Session()
{
- if (id())
- m_server->noteNode(id(), m_manualEndpoint, Origin::Unknown, true);
+ if (m_node)
+ {
+ if (id() && !isPermanentProblem(m_node->lastDisconnect) && !m_node->dead)
+ m_server->m_ready += m_node->index;
+ else
+ m_node->lastConnected = m_node->lastAttempted - chrono::seconds(1);
+ }
// Read-chain finished for one reason or another.
for (auto& i: m_capabilities)
@@ -125,8 +128,51 @@ template vector randomSelection(vector const& _t, unsigned _n)
return ret;
}
+void Session::ensureNodesRequested()
+{
+ if (isOpen() && !m_weRequestedNodes)
+ {
+ m_weRequestedNodes = true;
+ RLPStream s;
+ sealAndSend(prep(s, GetPeersPacket));
+ }
+}
+
+void Session::serviceNodesRequest()
+{
+ if (!m_theyRequestedNodes)
+ return;
+
+ auto peers = m_server->potentialPeers(m_knownNodes);
+ if (peers.empty())
+ {
+ addNote("peers", "requested");
+ return;
+ }
+
+ // note this should cost them...
+ RLPStream s;
+ prep(s, PeersPacket, min(10, peers.size()));
+ auto rs = randomSelection(peers, 10);
+ for (auto const& i: rs)
+ {
+ clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.address;
+ if (i.address.address().is_v4())
+ s.appendList(3) << bytesConstRef(i.address.address().to_v4().to_bytes().data(), 4) << i.address.port() << i.id;
+ else// if (i.second.address().is_v6()) - assumed
+ s.appendList(3) << bytesConstRef(i.address.address().to_v6().to_bytes().data(), 16) << i.address.port() << i.id;
+ m_knownNodes.extendAll(i.index);
+ m_knownNodes.unionWith(i.index);
+ }
+ sealAndSend(s);
+ m_theyRequestedNodes = false;
+ addNote("peers", "done");
+}
+
bool Session::interpret(RLP const& _r)
{
+ m_lastReceived = chrono::steady_clock::now();
+
clogS(NetRight) << _r;
try // Generic try-catch block designed to capture RLP format errors - TODO: give decent diagnostics, make a bit more specific over what is caught.
{
@@ -135,9 +181,6 @@ bool Session::interpret(RLP const& _r)
{
case HelloPacket:
{
- if (m_node)
- m_node->lastDisconnect = -1;
-
m_protocolVersion = _r[1].toInt();
auto clientVersion = _r[2].toString();
auto caps = _r[3].toVector();
@@ -152,12 +195,12 @@ bool Session::interpret(RLP const& _r)
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort;
- if (m_server->havePeer(id))
+ if (m_server->id() == id)
{
// Already connected.
- clogS(NetWarn) << "Already connected to a peer with id" << id.abridged();
- disconnect(DuplicatePeer);
- return false;
+ clogS(NetWarn) << "Connected to ourself under a false pretext. We were told this peer was id" << m_info.id.abridged();
+ disconnect(LocalIdentity);
+ return true;
}
if (m_node && m_node->id != id)
@@ -169,24 +212,41 @@ bool Session::interpret(RLP const& _r)
{
clogS(NetWarn) << "Connected to node, but their ID has changed since last time. This could indicate a MitM attack. Disconnecting.";
disconnect(UnexpectedIdentity);
- return false;
+ return true;
+ }
+
+ if (m_server->havePeer(id))
+ {
+ m_node->dead = true;
+ disconnect(DuplicatePeer);
+ return true;
}
}
+ if (m_server->havePeer(id))
+ {
+ // Already connected.
+ clogS(NetWarn) << "Already connected to a peer with id" << id.abridged();
+ disconnect(DuplicatePeer);
+ return true;
+ }
+
if (!id)
{
disconnect(NullIdentity);
- return false;
+ return true;
}
m_node = m_server->noteNode(id, bi::tcp::endpoint(m_socket.remote_endpoint().address(), listenPort), Origin::Self, false, !m_node || m_node->id == id ? NodeId() : m_node->id);
+ if (m_node->isOffline())
+ m_node->lastConnected = chrono::system_clock::now();
m_knownNodes.extendAll(m_node->index);
m_knownNodes.unionWith(m_node->index);
if (m_protocolVersion != m_server->protocolVersion())
{
disconnect(IncompatibleProtocol);
- return false;
+ return true;
}
m_info = PeerInfo({id, clientVersion, m_socket.remote_endpoint().address().to_string(), listenPort, std::chrono::steady_clock::duration(), _r[3].toSet(), (unsigned)m_socket.native_handle(), map() });
@@ -196,16 +256,16 @@ bool Session::interpret(RLP const& _r)
case DisconnectPacket:
{
string reason = "Unspecified";
- if (_r[1].isInt())
- reason = reasonOf((DisconnectReason)_r[1].toInt());
-
- clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
- if (m_socket.is_open())
- clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
+ auto r = (DisconnectReason)_r[1].toInt();
+ if (!_r[1].isInt())
+ drop(BadProtocol);
else
- clogS(NetNote) << "Remote closed.";
- m_socket.close();
- return false;
+ {
+ reason = reasonOf(r);
+ clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
+ drop(DisconnectRequested);
+ }
+ break;
}
case PingPacket:
{
@@ -221,27 +281,13 @@ bool Session::interpret(RLP const& _r)
case GetPeersPacket:
{
clogS(NetTriviaSummary) << "GetPeers";
- auto peers = m_server->potentialPeers(m_knownNodes);
- if (peers.empty())
- break;
- RLPStream s;
- prep(s, PeersPacket, min(10, peers.size()));
- auto rs = randomSelection(peers, 10);
- for (auto const& i: rs)
- {
- clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.address;
- if (i.address.address().is_v4())
- s.appendList(3) << bytesConstRef(i.address.address().to_v4().to_bytes().data(), 4) << i.address.port() << i.id;
- else// if (i.second.address().is_v6()) - assumed
- s.appendList(3) << bytesConstRef(i.address.address().to_v6().to_bytes().data(), 16) << i.address.port() << i.id;
- m_knownNodes.extendAll(i.index);
- m_knownNodes.unionWith(i.index);
- }
- sealAndSend(s);
+ m_theyRequestedNodes = true;
+ serviceNodesRequest();
break;
}
case PeersPacket:
clogS(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)";
+ m_weRequestedNodes = false;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
bi::address peerAddress;
@@ -252,7 +298,7 @@ bool Session::interpret(RLP const& _r)
else
{
disconnect(BadProtocol);
- return false;
+ return true;
}
auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt());
NodeId id = _r[i][2].toHash();
@@ -273,19 +319,29 @@ bool Session::interpret(RLP const& _r)
// check that it's not us or one we already know:
if (m_server->m_nodes.count(id))
{
+ /* MEH. Far from an ideal solution. Leave alone for now.
// Already got this node.
// See if it's any better that ours or not...
// This could be the public address of a known node.
// SECURITY: remove this in beta - it's only for lazy connections and presents an easy attack vector.
- if (m_server->m_nodes.count(id) && isPrivateAddress(m_server->m_nodes.at(id)->address.address()))
+ if (m_server->m_nodes.count(id) && isPrivateAddress(m_server->m_nodes.at(id)->address.address()) && ep.port() != 0)
// Update address if the node if we now have a public IP for it.
m_server->m_nodes[id]->address = ep;
+ */
goto CONTINUE;
}
if (!ep.port())
goto CONTINUE; // Zero port? Don't think so.
+ if (ep.port() >= 49152)
+ goto CONTINUE; // Private port according to IANA.
+
+ // TODO: PoC-7:
+ // Technically fine, but ignore for now to avoid peers passing on incoming ports until we can be sure that doesn't happen any more.
+// if (ep.port() < 30300 || ep.port() > 30305)
+// goto CONTINUE; // Wierd port.
+
// Avoid our random other addresses that they might end up giving us.
for (auto i: m_server->m_addresses)
if (ep.address() == i && ep.port() == m_server->listenPort())
@@ -314,10 +370,11 @@ bool Session::interpret(RLP const& _r)
}
}
}
- catch (...)
+ catch (std::exception const& _e)
{
+ clogS(NetWarn) << "Peer causing an exception:" << _e.what();
disconnect(BadProtocol);
- return false;
+ return true;
}
return true;
}
@@ -329,12 +386,6 @@ void Session::ping()
m_ping = std::chrono::steady_clock::now();
}
-void Session::getPeers()
-{
- RLPStream s;
- sealAndSend(prep(s, GetPeersPacket));
-}
-
RLPStream& Session::prep(RLPStream& _s, PacketType _id, unsigned _args)
{
return prep(_s).appendList(_args + 1).append((unsigned)_id);
@@ -350,7 +401,7 @@ void Session::sealAndSend(RLPStream& _s)
bytes b;
_s.swapOut(b);
m_server->seal(b);
- sendDestroy(b);
+ send(move(b));
}
bool Session::checkPacket(bytesConstRef _msg)
@@ -368,42 +419,26 @@ bool Session::checkPacket(bytesConstRef _msg)
return true;
}
-void Session::sendDestroy(bytes& _msg)
+void Session::send(bytesConstRef _msg)
{
- clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8));
-
- if (!checkPacket(bytesConstRef(&_msg)))
- {
- clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!";
- }
-
- bytes buffer = bytes(std::move(_msg));
- writeImpl(buffer);
+ send(_msg.toBytes());
}
-void Session::send(bytesConstRef _msg)
+void Session::send(bytes&& _msg)
{
- clogS(NetLeft) << RLP(_msg.cropped(8));
-
- if (!checkPacket(_msg))
- {
- clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!";
- }
+ clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8));
- bytes buffer = bytes(_msg.toBytes());
- writeImpl(buffer);
-}
+ if (!checkPacket(bytesConstRef(&_msg)))
+ clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!";
-void Session::writeImpl(bytes& _buffer)
-{
// cerr << (void*)this << " writeImpl" << endl;
if (!m_socket.is_open())
return;
bool doWrite = false;
{
- lock_guard l(m_writeLock);
- m_writeQueue.push_back(_buffer);
+ Guard l(x_writeQueue);
+ m_writeQueue.push_back(_msg);
doWrite = (m_writeQueue.size() == 1);
}
@@ -417,18 +452,16 @@ void Session::write()
auto self(shared_from_this());
ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/)
{
-// cerr << (void*)this << " write.callback" << endl;
-
// must check queue, as write callback can occur following dropped()
if (ec)
{
clogS(NetWarn) << "Error sending: " << ec.message();
- dropped();
+ drop(TCPError);
return;
}
else
{
- lock_guard l(m_writeLock);
+ Guard l(x_writeQueue);
m_writeQueue.pop_front();
if (m_writeQueue.empty())
return;
@@ -437,37 +470,43 @@ void Session::write()
});
}
-void Session::dropped()
+void Session::drop(DisconnectReason _reason)
{
-// cerr << (void*)this << " dropped" << endl;
+ if (m_dropped)
+ return;
+ cerr << (void*)this << " dropped" << endl;
if (m_socket.is_open())
try
{
- clogS(NetConnect) << "Closing " << m_socket.remote_endpoint();
+ clogS(NetConnect) << "Closing " << m_socket.remote_endpoint() << "(" << reasonOf(_reason) << ")";
m_socket.close();
}
catch (...) {}
-}
-
-void Session::disconnect(int _reason)
-{
- clogS(NetConnect) << "Disconnecting (reason:" << reasonOf((DisconnectReason)_reason) << ")";
if (m_node)
+ {
+ if (_reason != m_node->lastDisconnect || _reason == NoDisconnect || _reason == ClientQuit || _reason == DisconnectRequested)
+ m_node->failedAttempts = 0;
m_node->lastDisconnect = _reason;
+ if (_reason == BadProtocol)
+ {
+ m_node->rating /= 2;
+ m_node->score /= 2;
+ }
+ }
+ m_dropped = true;
+}
+void Session::disconnect(DisconnectReason _reason)
+{
+ clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")";
if (m_socket.is_open())
{
- if (m_disconnect == chrono::steady_clock::time_point::max())
- {
- RLPStream s;
- prep(s, DisconnectPacket, 1) << _reason;
- sealAndSend(s);
- m_disconnect = chrono::steady_clock::now();
- }
- else
- dropped();
+ RLPStream s;
+ prep(s, DisconnectPacket, 1) << (int)_reason;
+ sealAndSend(s);
}
+ drop(_reason);
}
void Session::start()
@@ -481,15 +520,13 @@ void Session::start()
<< m_server->id();
sealAndSend(s);
ping();
- getPeers();
-
doRead();
}
void Session::doRead()
{
// ignore packets received while waiting to disconnect
- if (chrono::steady_clock::now() - m_disconnect > chrono::seconds(0))
+ if (m_dropped)
return;
auto self(shared_from_this());
@@ -500,7 +537,7 @@ void Session::doRead()
{
// got here with length of 1241...
clogS(NetWarn) << "Error reading: " << ec.message();
- dropped();
+ drop(TCPError);
}
else if (ec && length == 0)
{
@@ -541,8 +578,8 @@ void Session::doRead()
RLP r(data.cropped(8));
if (!interpret(r))
{
- // error
- dropped();
+ // error - bad protocol
+ disconnect(BadProtocol);
return;
}
}
@@ -555,12 +592,12 @@ void Session::doRead()
catch (Exception const& _e)
{
clogS(NetWarn) << "ERROR: " << diagnostic_information(_e);
- dropped();
+ drop(BadProtocol);
}
catch (std::exception const& _e)
{
clogS(NetWarn) << "ERROR: " << _e.what();
- dropped();
+ drop(BadProtocol);
}
}
});
diff --git a/libp2p/Session.h b/libp2p/Session.h
index ff05be81b..e8de1c398 100644
--- a/libp2p/Session.h
+++ b/libp2p/Session.h
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include "Common.h"
namespace dev
@@ -38,7 +39,7 @@ namespace dev
namespace p2p
{
-class Node;
+struct Node;
/**
* @brief The Session class
@@ -55,7 +56,7 @@ public:
virtual ~Session();
void start();
- void disconnect(int _reason);
+ void disconnect(DisconnectReason _reason);
void ping();
@@ -72,7 +73,7 @@ public:
static RLPStream& prep(RLPStream& _s, PacketType _t, unsigned _args = 0);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
- void sendDestroy(bytes& _msg);
+ void send(bytes&& _msg);
void send(bytesConstRef _msg);
int rating() const;
@@ -82,42 +83,50 @@ public:
PeerInfo const& info() const { return m_info; }
+ void ensureNodesRequested();
+ void serviceNodesRequest();
+
private:
- void dropped();
+ /// Drop the connection for the reason @a _r.
+ void drop(DisconnectReason _r);
+
+ /// Perform a read on the socket.
void doRead();
- void doWrite(std::size_t length);
- void writeImpl(bytes& _buffer);
+
+ /// Perform a single round of the write operation. This could end up calling itself asynchronously.
void write();
- void getPeers();
+ /// Interpret an incoming message.
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
static bool checkPacket(bytesConstRef _msg);
- Host* m_server;
+ Host* m_server; ///< The host that owns us. Never null.
- std::mutex m_writeLock;
- std::deque m_writeQueue;
+ mutable bi::tcp::socket m_socket; ///< Socket for the peer's connection. Mutable to ask for native_handle().
+ Mutex x_writeQueue; ///< Mutex for the write queue.
+ std::deque m_writeQueue; ///< The write queue.
+ std::array m_data; ///< Data buffer for the write queue.
+ bytes m_incoming; ///< The incoming read queue of bytes.
- mutable bi::tcp::socket m_socket; ///< Mutable to ask for native_handle().
- std::array m_data;
- PeerInfo m_info;
+ PeerInfo m_info; ///< Dyanamic information about this peer.
- bytes m_incoming;
- unsigned m_protocolVersion;
- std::shared_ptr m_node;
- bi::tcp::endpoint m_manualEndpoint;
- bool m_force = false; /// If true, ignore IDs being different. This could open you up to MitM attacks.
+ unsigned m_protocolVersion = 0; ///< The protocol version of the peer.
+ std::shared_ptr m_node; ///< The Node object. Might be null if we constructed using a bare address/port.
+ bi::tcp::endpoint m_manualEndpoint; ///< The endpoint as specified by the constructor.
+ bool m_force = false; ///< If true, ignore IDs being different. This could open you up to MitM attacks.
+ bool m_dropped = false; ///< If true, we've already divested ourselves of this peer. We're just waiting for the reads & writes to fail before the shared_ptr goes OOS and the destructor kicks in.
- std::chrono::steady_clock::time_point m_ping;
- std::chrono::steady_clock::time_point m_connect;
- std::chrono::steady_clock::time_point m_disconnect;
+ bool m_theyRequestedNodes = false; ///< Has the peer requested nodes from us without receiveing an answer from us?
+ bool m_weRequestedNodes = false; ///< Have we requested nodes from the peer and not received an answer yet?
- std::map> m_capabilities;
- RangeMask m_knownNodes; ///< Nodes we already know about as indices into Host's nodesList. These shouldn't be resent to peer.
+ std::chrono::steady_clock::time_point m_connect; ///< Time point of connection.
+ std::chrono::steady_clock::time_point m_ping; ///< Time point of last ping.
+ std::chrono::steady_clock::time_point m_lastReceived; ///< Time point of last message.
- bool m_willBeDeleted = false; ///< True if we already posted a deleter on the strand.
+ std::map> m_capabilities; ///< The peer's capability set.
+ RangeMask m_knownNodes; ///< Nodes we already know about as indices into Host's nodesList. These shouldn't be resent to peer.
};
}
diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp
index a244b9c9b..e85d381f8 100644
--- a/libqethereum/QEthereum.cpp
+++ b/libqethereum/QEthereum.cpp
@@ -1,7 +1,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -396,7 +395,7 @@ static QString toJson(dev::eth::Transaction const& _bi)
v["from"] = toQJS(_bi.sender());
v["gas"] = (int)_bi.gas;
v["gasPrice"] = toQJS(_bi.gasPrice);
- v["nonce"] = toQJS(_bi.nonce);
+ v["nonce"] = (int)_bi.nonce;
v["value"] = toQJS(_bi.value);
return QString::fromUtf8(QJsonDocument(v).toJson());
diff --git a/libqethereum/QmlEthereum.cpp b/libqethereum/QmlEthereum.cpp
index 89578a29a..a7ed3df4d 100644
--- a/libqethereum/QmlEthereum.cpp
+++ b/libqethereum/QmlEthereum.cpp
@@ -4,7 +4,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h
index fd0991eaa..32bbe0b31 100644
--- a/libwebthree/WebThree.h
+++ b/libwebthree/WebThree.h
@@ -108,6 +108,11 @@ public:
void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); }
+ p2p::NodeId id() const { return m_net.id(); }
+
+ /// Gets the nodes.
+ p2p::Nodes nodes() const { return m_net.nodes(); }
+
/// Start the network subsystem.
void startNetwork() { m_net.start(); }
diff --git a/test/dagger.cpp b/test/dagger.cpp
index 555c5d776..9422b6a96 100644
--- a/test/dagger.cpp
+++ b/test/dagger.cpp
@@ -17,12 +17,12 @@
/** @file dagger.cpp
* @author Gav Wood
* @date 2014
- * Dagger test functions.
+ * ProofOfWork test functions.
*/
#include
#include
-#include
+#include
using namespace std;
using namespace std::chrono;
using namespace dev;
@@ -30,20 +30,20 @@ using namespace dev::eth;
int daggerTest()
{
- cnote << "Testing Dagger...";
+ cnote << "Testing ProofOfWork...";
// Test dagger
{
auto s = steady_clock::now();
- cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)0);
+ cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)0);
cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl;
- cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)1);
+ cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)1);
cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl;
}
{
auto s = steady_clock::now();
- cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)0);
+ cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)0);
cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl;
- cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)1);
+ cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)1);
cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl;
}
return 0;
diff --git a/third/MainWin.cpp b/third/MainWin.cpp
index 399fc8396..d21077f86 100644
--- a/third/MainWin.cpp
+++ b/third/MainWin.cpp
@@ -30,7 +30,6 @@
#include
#include
#include
-#include
#include
#include
#include