diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9ed54656f..3d055587c 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)
+# propagates CMake configuration options to the compiler
+function(configureProject)
+ if (LANGUAGES)
add_definitions(-DETH_LANGUAGES)
-endif ()
+ endif ()
-if (PARANOIA)
+ 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 (VMTRACE)
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_definitions(-DETH_VMTRACE)
else ()
message(FATAL_ERROR "VM tracing requires debug.")
endif ()
-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 ()
+ set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/unknown")
+ 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})
+
+ 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}")
-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 ()
+include(EthDependenciesDeprecated)
- 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()
-
-# 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 (NOT LANGUAGES)
@@ -379,9 +161,6 @@ if (EVMCC)
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/CMakeLists.txt b/alethzero/CMakeLists.txt
index c5d1aa0be..4ad06f7a6 100644
--- a/alethzero/CMakeLists.txt
+++ b/alethzero/CMakeLists.txt
@@ -25,6 +25,7 @@ find_package(Qt5WebKitWidgets REQUIRED)
qt5_wrap_ui(ui_Main.h Main.ui)
# Set name of binary and add_executable()
+file(GLOB HEADERS "*.h")
if (APPLE)
set(EXECUTEABLE AlethZero)
set(BIN_INSTALL_DIR ".")
@@ -41,14 +42,14 @@ if (APPLE)
set(MACOSX_BUNDLE_ICON_FILE alethzero)
include(BundleUtilities)
- add_executable(${EXECUTEABLE} MACOSX_BUNDLE alethzero.icns Main.ui ${SRC_LIST})
+ add_executable(${EXECUTEABLE} MACOSX_BUNDLE alethzero.icns Main.ui ${SRC_LIST} ${HEADERS})
set_target_properties(${EXECUTEABLE} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/EthereumMacOSXBundleInfo.plist.in")
SET_SOURCE_FILES_PROPERTIES(${EXECUTEABLE} PROPERTIES MACOSX_PACKAGE_LOCATION MacOS)
SET_SOURCE_FILES_PROPERTIES(${MACOSX_BUNDLE_ICON_FILE}.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
else ()
set(EXECUTEABLE alethzero)
- add_executable(${EXECUTEABLE} Main.ui ${SRC_LIST})
+ add_executable(${EXECUTEABLE} Main.ui ${SRC_LIST} ${HEADERS})
endif ()
qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets)
diff --git a/alethzero/DownloadView.cpp b/alethzero/DownloadView.cpp
index a6533023c..88a595566 100644
--- a/alethzero/DownloadView.cpp
+++ b/alethzero/DownloadView.cpp
@@ -45,7 +45,7 @@ void DownloadView::paintEvent(QPaintEvent*)
double ratio = (double)rect().width() / rect().height();
if (ratio < 1)
ratio = 1 / ratio;
- double n = min(rect().width(), rect().height()) / ceil(sqrt(m_man->chain().size() / ratio));
+ double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(m_man->chain().size() / ratio)));
// QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n));
QSizeF area(n, n);
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 5455c27ea..8d69727f8 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -33,7 +33,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -207,6 +206,12 @@ unsigned Main::installWatch(dev::h256 _tf, std::function const& _f)
return ret;
}
+void Main::uninstallWatch(unsigned _w)
+{
+ ethereum()->uninstallWatch(_w);
+ m_handlers.erase(_w);
+}
+
void Main::installWatches()
{
installWatch(dev::eth::MessageFilter().altered(c_config, 0), [=](){ installNameRegWatch(); });
@@ -217,13 +222,13 @@ void Main::installWatches()
void Main::installNameRegWatch()
{
- ethereum()->uninstallWatch(m_nameRegFilter);
+ uninstallWatch(m_nameRegFilter);
m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
}
void Main::installCurrenciesWatch()
{
- ethereum()->uninstallWatch(m_currenciesFilter);
+ uninstallWatch(m_currenciesFilter);
m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); });
}
@@ -242,7 +247,7 @@ void Main::installBalancesWatch()
tf.altered(c, (u160)i.address());
}
- ethereum()->uninstallWatch(m_balancesFilter);
+ uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); });
}
@@ -500,7 +505,7 @@ void Main::writeSettings()
s.setValue("privateChain", m_privateChain);
s.setValue("verbosity", ui->verbosity->value());
- bytes d = m_webThree->savePeers();
+ bytes d = m_webThree->saveNodes();
if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_peers);
@@ -745,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()
@@ -866,7 +900,7 @@ void Main::refreshBlockChain()
string filter = ui->blockChainFilter->text().toLower().toStdString();
auto const& bc = ethereum()->blockChain();
unsigned i = (ui->showAll->isChecked() || !filter.empty()) ? (unsigned)-1 : 10;
- for (auto h = bc.currentHash(); h != bc.genesisHash() && bc.details(h) && i; h = bc.details(h).parent, --i)
+ for (auto h = bc.currentHash(); bc.details(h) && i; h = bc.details(h).parent, --i)
{
auto d = bc.details(h);
auto bm = blockMatch(filter, d, h, bc);
@@ -906,6 +940,8 @@ void Main::refreshBlockChain()
}
n++;
}
+ if (h == bc.genesisHash())
+ break;
}
if (!ui->blocks->currentItem())
@@ -940,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)
@@ -1132,7 +1168,10 @@ void Main::on_blocks_currentItemChanged()
s << "
Bloom: " << details.bloom << "";
s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "";
s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "";
- s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "";
+ if (info.parentHash)
+ s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "";
+ else
+ s << "
Pre: Nothing is before the Gensesis";
for (auto const& i: block[1])
s << "
" << sha3(i[0].data()).abridged() << ": " << i[1].toHash() << " [" << i[2].toInt() << " used]";
s << "
Post: " << info.stateRoot << "";
@@ -1257,10 +1296,10 @@ void Main::populateDebugger(dev::bytesConstRef _r)
if (!m_codes.count(lastDataHash))
m_codes[lastDataHash] = ext.data.toBytes();
}
- if (levels.size() < ext.level)
+ if (levels.size() < ext.depth)
levels.push_back(&m_history.back());
else
- levels.resize(ext.level);
+ levels.resize(ext.depth);
m_history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
m_currentExecution->go(onOp);
@@ -1539,10 +1578,10 @@ void Main::on_net_triggered()
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0);
+ if (m_peers.size()/* && ui->usePast->isChecked()*/)
+ web3()->restoreNodes(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
- if (m_peers.size() && ui->usePast->isChecked())
- web3()->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
}
else
{
@@ -1701,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/alethzero/MainWin.h b/alethzero/MainWin.h
index c83848cdd..55b8b4e0a 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -183,6 +183,7 @@ private:
unsigned installWatch(dev::eth::MessageFilter const& _tf, std::function const& _f);
unsigned installWatch(dev::h256 _tf, std::function const& _f);
+ void uninstallWatch(unsigned _w);
void keysChanged();
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/CMakeLists.txt b/eth/CMakeLists.txt
index eee1d258b..087c5314a 100644
--- a/eth/CMakeLists.txt
+++ b/eth/CMakeLists.txt
@@ -8,7 +8,8 @@ link_directories(../libwebthree)
set(EXECUTABLE eth)
-add_executable(${EXECUTABLE} ${SRC_LIST})
+file(GLOB HEADERS "*.h")
+add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1)
diff --git a/eth/main.cpp b/eth/main.cpp
index 03be8b969..b5e8eb736 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;
@@ -612,42 +627,50 @@ int main(int argc, char** argv)
Transaction t = state.pending()[index];
state = state.fromPending(index);
bytes r = t.rlp();
- 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->level << " | " << 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)
+ 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 << 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);
+ 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);
+ }
}
}
else if (c && cmd == "inspect")
@@ -757,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();
@@ -765,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/evmcc/bytecode/if1.evm b/evmcc/bytecode/if1.evm
deleted file mode 100644
index ee9009294..000000000
--- a/evmcc/bytecode/if1.evm
+++ /dev/null
@@ -1 +0,0 @@
-600160805460006080530b6016596003608054601b586002608054
diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp
index 22ba1db50..9cf731419 100644
--- a/evmcc/evmcc.cpp
+++ b/evmcc/evmcc.cpp
@@ -12,9 +12,8 @@
#include
#include
#include
-
-#include "Compiler.h"
-#include "ExecutionEngine.h"
+#include
+#include
void show_usage()
@@ -95,7 +94,7 @@ int main(int argc, char** argv)
if (opt_compile)
{
auto compiler = eth::jit::Compiler();
- auto module = compiler.compile(bytecode);
+ auto module = compiler.compile({bytecode.data(), bytecode.size()});
llvm::raw_os_ostream out(std::cout);
module->print(out, nullptr);
@@ -111,9 +110,10 @@ int main(int argc, char** argv)
if (opt_interpret)
{
auto engine = eth::jit::ExecutionEngine();
- auto module = eth::jit::Compiler().compile(bytecode);
+ auto module = eth::jit::Compiler().compile({bytecode.data(), bytecode.size()});
module->dump();
- auto result = engine.run(std::move(module));
+ u256 gas = 10000;
+ auto result = engine.run(std::move(module), gas);
return result;
}
diff --git a/evmcc/lll/if1.asm b/evmcc/lll/if1.asm
deleted file mode 100644
index 4a938adce..000000000
--- a/evmcc/lll/if1.asm
+++ /dev/null
@@ -1,21 +0,0 @@
-.code:
- PUSH 1
- PUSH 128
- MSTORE
- PUSH 0
- PUSH 128
- MLOAD
- GT
- PUSH [tag0]
- JUMPI
- PUSH 3
- PUSH 128
- MSTORE
- PUSH [tag1]
- JUMP
-tag0:
- PUSH 2
- PUSH 128
- MSTORE
-tag1:
-
diff --git a/evmcc/lll/if1.lll b/evmcc/lll/if1.lll
deleted file mode 100644
index 7984807c1..000000000
--- a/evmcc/lll/if1.lll
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- [i] 1
-
- ( if (> @i 0) [i] 2 [i] 3 )
-}
diff --git a/evmcc/bytecode/arithmetic_test.evm b/evmcc/test/arith/arith1.evm
similarity index 100%
rename from evmcc/bytecode/arithmetic_test.evm
rename to evmcc/test/arith/arith1.evm
diff --git a/evmcc/lll/arithmetic_test.lll b/evmcc/test/arith/arith1.lll
similarity index 100%
rename from evmcc/lll/arithmetic_test.lll
rename to evmcc/test/arith/arith1.lll
diff --git a/evmcc/bytecode/fib1.evm b/evmcc/test/arith/fib1.evm
similarity index 100%
rename from evmcc/bytecode/fib1.evm
rename to evmcc/test/arith/fib1.evm
diff --git a/evmcc/lll/fib1.lll b/evmcc/test/arith/fib1.lll
similarity index 100%
rename from evmcc/lll/fib1.lll
rename to evmcc/test/arith/fib1.lll
diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/test/ext/ext_test.evm
similarity index 100%
rename from evmcc/bytecode/ext_test.evm
rename to evmcc/test/ext/ext_test.evm
diff --git a/evmcc/lll/ext_test.lll b/evmcc/test/ext/ext_test.lll
similarity index 100%
rename from evmcc/lll/ext_test.lll
rename to evmcc/test/ext/ext_test.lll
diff --git a/evmcc/bytecode/store_test.evm b/evmcc/test/ext/store_test.evm
similarity index 100%
rename from evmcc/bytecode/store_test.evm
rename to evmcc/test/ext/store_test.evm
diff --git a/evmcc/lll/store_test.lll b/evmcc/test/ext/store_test.lll
similarity index 100%
rename from evmcc/lll/store_test.lll
rename to evmcc/test/ext/store_test.lll
diff --git a/evmcc/bytecode/for1.evm b/evmcc/test/jump/for1.evm
similarity index 100%
rename from evmcc/bytecode/for1.evm
rename to evmcc/test/jump/for1.evm
diff --git a/evmcc/lll/for1.lll b/evmcc/test/jump/for1.lll
similarity index 100%
rename from evmcc/lll/for1.lll
rename to evmcc/test/jump/for1.lll
diff --git a/evmcc/bytecode/for2.evm b/evmcc/test/jump/for2.evm
similarity index 100%
rename from evmcc/bytecode/for2.evm
rename to evmcc/test/jump/for2.evm
diff --git a/evmcc/lll/for2.lll b/evmcc/test/jump/for2.lll
similarity index 100%
rename from evmcc/lll/for2.lll
rename to evmcc/test/jump/for2.lll
diff --git a/evmcc/lll/when1.asm b/evmcc/test/jump/when1.asm
similarity index 100%
rename from evmcc/lll/when1.asm
rename to evmcc/test/jump/when1.asm
diff --git a/evmcc/bytecode/when1.evm b/evmcc/test/jump/when1.evm
similarity index 100%
rename from evmcc/bytecode/when1.evm
rename to evmcc/test/jump/when1.evm
diff --git a/evmcc/lll/when1.lll b/evmcc/test/jump/when1.lll
similarity index 100%
rename from evmcc/lll/when1.lll
rename to evmcc/test/jump/when1.lll
diff --git a/evmcc/bytecode/kv.evm b/evmcc/test/kv.evm
similarity index 100%
rename from evmcc/bytecode/kv.evm
rename to evmcc/test/kv.evm
diff --git a/evmcc/lll/kv.lll b/evmcc/test/kv.lll
similarity index 100%
rename from evmcc/lll/kv.lll
rename to evmcc/test/kv.lll
diff --git a/evmcc/bytecode/byte.evm b/evmcc/test/mem/byte.evm
similarity index 100%
rename from evmcc/bytecode/byte.evm
rename to evmcc/test/mem/byte.evm
diff --git a/evmcc/lll/byte.lll b/evmcc/test/mem/byte.lll
similarity index 100%
rename from evmcc/lll/byte.lll
rename to evmcc/test/mem/byte.lll
diff --git a/evmcc/bytecode/mem2.evm b/evmcc/test/mem/mem2.evm
similarity index 100%
rename from evmcc/bytecode/mem2.evm
rename to evmcc/test/mem/mem2.evm
diff --git a/evmcc/lll/mem2.lll b/evmcc/test/mem/mem2.lll
similarity index 100%
rename from evmcc/lll/mem2.lll
rename to evmcc/test/mem/mem2.lll
diff --git a/evmcc/bytecode/memtest1.evm b/evmcc/test/mem/memtest1.evm
similarity index 100%
rename from evmcc/bytecode/memtest1.evm
rename to evmcc/test/mem/memtest1.evm
diff --git a/evmcc/lll/memtest1.lll b/evmcc/test/mem/memtest1.lll
similarity index 100%
rename from evmcc/lll/memtest1.lll
rename to evmcc/test/mem/memtest1.lll
diff --git a/evmcc/bytecode/return1.evm b/evmcc/test/ret/return1.evm
similarity index 100%
rename from evmcc/bytecode/return1.evm
rename to evmcc/test/ret/return1.evm
diff --git a/evmcc/lll/return1.lll b/evmcc/test/ret/return1.lll
similarity index 100%
rename from evmcc/lll/return1.lll
rename to evmcc/test/ret/return1.lll
diff --git a/evmcc/bytecode/return2.evm b/evmcc/test/ret/return2.evm
similarity index 100%
rename from evmcc/bytecode/return2.evm
rename to evmcc/test/ret/return2.evm
diff --git a/evmcc/lll/return2.lll b/evmcc/test/ret/return2.lll
similarity index 100%
rename from evmcc/lll/return2.lll
rename to evmcc/test/ret/return2.lll
diff --git a/evmcc/bytecode/return_test.evm b/evmcc/test/ret/return_test.evm
similarity index 100%
rename from evmcc/bytecode/return_test.evm
rename to evmcc/test/ret/return_test.evm
diff --git a/evmcc/lll/return_test.lll b/evmcc/test/ret/return_test.lll
similarity index 100%
rename from evmcc/lll/return_test.lll
rename to evmcc/test/ret/return_test.lll
diff --git a/evmcc/bytecode/push_test.evm b/evmcc/test/stack/push_test.evm
similarity index 100%
rename from evmcc/bytecode/push_test.evm
rename to evmcc/test/stack/push_test.evm
diff --git a/evmcc/lll/push_test.lll b/evmcc/test/stack/push_test.lll
similarity index 100%
rename from evmcc/lll/push_test.lll
rename to evmcc/test/stack/push_test.lll
diff --git a/evmcc/bytecode/stack_test.evm b/evmcc/test/stack/stack_test.evm
similarity index 100%
rename from evmcc/bytecode/stack_test.evm
rename to evmcc/test/stack/stack_test.evm
diff --git a/evmcc/lll/stack_test.lll b/evmcc/test/stack/stack_test.lll
similarity index 100%
rename from evmcc/lll/stack_test.lll
rename to evmcc/test/stack/stack_test.lll
diff --git a/evmcc/bytecode/stackjump.evm b/evmcc/test/stack/stackjump.evm
similarity index 100%
rename from evmcc/bytecode/stackjump.evm
rename to evmcc/test/stack/stackjump.evm
diff --git a/evmcc/lll/stackjump.lll b/evmcc/test/stack/stackjump.lll
similarity index 100%
rename from evmcc/lll/stackjump.lll
rename to evmcc/test/stack/stackjump.lll
diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt
index 3f3ecb619..81e210cad 100644
--- a/libdevcore/CMakeLists.txt
+++ b/libdevcore/CMakeLists.txt
@@ -10,13 +10,12 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE devcore)
-# set(CMAKE_INSTALL_PREFIX ../lib)
+file(GLOB HEADERS "*.h")
if(ETH_STATIC)
- add_library(${EXECUTABLE} STATIC ${SRC_LIST})
+ add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
- add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
-file(GLOB HEADERS "*.h")
include_directories(..)
diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp
index fd1868539..335e2b387 100644
--- a/libdevcore/Common.cpp
+++ b/libdevcore/Common.cpp
@@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
-char const* Version = "0.7.1";
+char const* Version = "0.7.4";
}
diff --git a/libdevcore/Common.h b/libdevcore/Common.h
index 332081ec8..87cc069b3 100644
--- a/libdevcore/Common.h
+++ b/libdevcore/Common.h
@@ -38,6 +38,7 @@
#include
#include
#include "vector_ref.h"
+#include "debugbreak.h"
// CryptoPP defines byte in the global namespace, so must we.
using byte = uint8_t;
@@ -103,4 +104,45 @@ inline unsigned int toLog2(u256 _x)
return ret;
}
+// Assertions...
+
+#if defined(_MSC_VER)
+#define ETH_FUNC __FUNCSIG__
+#elif defined(__GNUC__)
+#define ETH_FUNC __PRETTY_FUNCTION__
+#else
+#define ETH_FUNC __func__
+#endif
+
+#define asserts(A) ::dev::assertAux(A, #A, __LINE__, __FILE__, ETH_FUNC)
+#define assertsEqual(A, B) ::dev::assertEqualAux(A, B, #A, #B, __LINE__, __FILE__, ETH_FUNC)
+
+inline bool assertAux(bool _a, char const* _aStr, unsigned _line, char const* _file, char const* _func)
+{
+ bool ret = _a;
+ if (!ret)
+ {
+ std::cerr << "Assertion failed:" << _aStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl;
+#if ETH_DEBUG
+ debug_break();
+#endif
+ }
+ return !ret;
+}
+
+template
+inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char const* _bStr, unsigned _line, char const* _file, char const* _func)
+{
+ bool ret = _a == _b;
+ if (!ret)
+ {
+ std::cerr << "Assertion failed: " << _aStr << " == " << _bStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl;
+ std::cerr << " Fail equality: " << _a << "==" << _b << std::endl;
+#if ETH_DEBUG
+ debug_break();
+#endif
+ }
+ return !ret;
+}
+
}
diff --git a/libdevcore/RangeMask.h b/libdevcore/RangeMask.h
index e6a66776c..ac58ec8b1 100644
--- a/libdevcore/RangeMask.h
+++ b/libdevcore/RangeMask.h
@@ -47,6 +47,7 @@ public:
RangeMask(T _begin, T _end): m_all(_begin, _end) {}
RangeMask(Range const& _c): m_all(_c) {}
+ RangeMask unionedWith(RangeMask const& _m) const { return operator+(_m); }
RangeMask operator+(RangeMask const& _m) const { return RangeMask(*this) += _m; }
RangeMask lowest(T _items) const
@@ -57,7 +58,9 @@ public:
return ret;
}
- RangeMask operator~() const
+ RangeMask operator~() const { return inverted(); }
+
+ RangeMask inverted() const
{
RangeMask ret(m_all);
T last = m_all.first;
@@ -72,16 +75,28 @@ public:
return ret;
}
- RangeMask& operator+=(RangeMask const& _m)
+ RangeMask& invert() { return *this = inverted(); }
+
+ template RangeMask operator-(S const& _m) const { auto ret = *this; return ret -= _m; }
+ template RangeMask& operator-=(S const& _m) { return invert().unionWith(_m).invert(); }
+
+ RangeMask& operator+=(RangeMask const& _m) { return unionWith(_m); }
+
+ RangeMask& unionWith(RangeMask const& _m)
{
+ m_all.first = std::min(_m.m_all.first, m_all.first);
+ m_all.second = std::max(_m.m_all.second, m_all.second);
for (auto const& i: _m.m_ranges)
- operator+=(i);
+ unionWith(i);
return *this;
}
- RangeMask& operator+=(UnsignedRange const& _m)
+ RangeMask& operator+=(Range const& _m) { return unionWith(_m); }
+ RangeMask& unionWith(Range const& _m)
{
for (auto i = _m.first; i < _m.second;)
{
+ assert(i >= m_all.first);
+ assert(i < m_all.second);
// for each number, we find the element equal or next lower. this, if any, must contain the value.
auto uit = m_ranges.upper_bound(i);
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit);
@@ -130,7 +145,8 @@ public:
return *this;
}
- RangeMask& operator+=(T _i)
+ RangeMask& operator+=(T _m) { return unionWith(_m); }
+ RangeMask& unionWith(T _i)
{
return operator+=(Range(_i, _i + 1));
}
@@ -165,6 +181,7 @@ public:
}
std::pair const& all() const { return m_all; }
+ void extendAll(T _i) { m_all = std::make_pair(std::min(m_all.first, _i), std::max(m_all.second, _i + 1)); }
class const_iterator
{
diff --git a/libdevcore/debugbreak.h b/libdevcore/debugbreak.h
new file mode 100644
index 000000000..57d9d8cde
--- /dev/null
+++ b/libdevcore/debugbreak.h
@@ -0,0 +1,121 @@
+/* Copyright (c) 2013, Scott Tsai
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DEBUG_BREAK_H
+#define DEBUG_BREAK_H
+
+#ifdef _MSC_VER
+
+#define debug_break __debugbreak
+
+#else
+
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ /* gcc optimizers consider code after __builtin_trap() dead.
+ * Making __builtin_trap() unsuitable for breaking into the debugger */
+ DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP = 0,
+};
+
+#if defined(__i386__) || defined(__x86_64__)
+enum { HAVE_TRAP_INSTRUCTION = 1, };
+__attribute__((gnu_inline, always_inline))
+static void __inline__ trap_instruction(void)
+{
+ __asm__ volatile("int $0x03");
+}
+#elif defined(__thumb__)
+enum { HAVE_TRAP_INSTRUCTION = 1, };
+/* FIXME: handle __THUMB_INTERWORK__ */
+__attribute__((gnu_inline, always_inline))
+static void __inline__ trap_instruction(void)
+{
+ /* See 'arm-linux-tdep.c' in GDB source.
+ * Both instruction sequences below works. */
+#if 1
+ /* 'eabi_linux_thumb_le_breakpoint' */
+ __asm__ volatile(".inst 0xde01");
+#else
+ /* 'eabi_linux_thumb2_le_breakpoint' */
+ __asm__ volatile(".inst.w 0xf7f0a000");
+#endif
+
+ /* Known problem:
+ * After a breakpoint hit, can't stepi, step, or continue in GDB.
+ * 'step' stuck on the same instruction.
+ *
+ * Workaround: a new GDB command,
+ * 'debugbreak-step' is defined in debugbreak-gdb.py
+ * that does:
+ * (gdb) set $instruction_len = 2
+ * (gdb) tbreak *($pc + $instruction_len)
+ * (gdb) jump *($pc + $instruction_len)
+ */
+}
+#elif defined(__arm__) && !defined(__thumb__)
+enum { HAVE_TRAP_INSTRUCTION = 1, };
+__attribute__((gnu_inline, always_inline))
+static void __inline__ trap_instruction(void)
+{
+ /* See 'arm-linux-tdep.c' in GDB source,
+ * 'eabi_linux_arm_le_breakpoint' */
+ __asm__ volatile(".inst 0xe7f001f0");
+ /* Has same known problem and workaround
+ * as Thumb mode */
+}
+#else
+enum { HAVE_TRAP_INSTRUCTION = 0, };
+#endif
+
+__attribute__((gnu_inline, always_inline))
+static void __inline__ debug_break(void)
+{
+ if (HAVE_TRAP_INSTRUCTION) {
+ trap_instruction();
+ } else if (DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP) {
+ /* raises SIGILL on Linux x86{,-64}, to continue in gdb:
+ * (gdb) handle SIGILL stop nopass
+ * */
+ __builtin_trap();
+ } else {
+ raise(SIGTRAP);
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
diff --git a/libdevcrypto/CMakeLists.txt b/libdevcrypto/CMakeLists.txt
index e7f112f95..cee7d130d 100644
--- a/libdevcrypto/CMakeLists.txt
+++ b/libdevcrypto/CMakeLists.txt
@@ -4,15 +4,13 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE devcrypto)
-# set(CMAKE_INSTALL_PREFIX ../lib)
+file(GLOB HEADERS "*.h")
if(ETH_STATIC)
- add_library(${EXECUTABLE} STATIC ${SRC_LIST})
+ add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
- add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
-file(GLOB HEADERS "*.h")
-
include_directories(..)
target_link_libraries(${EXECUTABLE} devcore)
diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp
index dd4d6961c..8863352a4 100644
--- a/libdevcrypto/Common.cpp
+++ b/libdevcrypto/Common.cpp
@@ -39,7 +39,8 @@ Address dev::toAddress(Secret _private)
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0);
- assert(pubkeylen == 65);
+ if (asserts(pubkeylen == 65))
+ return Address();
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
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 d4583dc9b..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 {};
@@ -473,7 +473,7 @@ template void GenericTrieDB::insert(bytesConstRef _key, bytesCons
assert(rv.size());
bytes b = mergeAt(RLP(rv), NibbleSlice(_key), _value);
- // mergeAt won't attempt to delete the node is it's less than 32 bytes
+ // mergeAt won't attempt to delete the node if it's less than 32 bytes
// However, we know it's the root node and thus always hashed.
// So, if it's less than 32 (and thus should have been deleted but wasn't) then we delete it here.
if (rv.size() < 32)
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/CMakeLists.txt b/libethcore/CMakeLists.txt
index 6aba644f1..f5cf00b57 100644
--- a/libethcore/CMakeLists.txt
+++ b/libethcore/CMakeLists.txt
@@ -4,15 +4,13 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE ethcore)
-# set(CMAKE_INSTALL_PREFIX ../lib)
+file(GLOB HEADERS "*.h")
if(ETH_STATIC)
- add_library(${EXECUTABLE} STATIC ${SRC_LIST})
+ add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
- add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
-file(GLOB HEADERS "*.h")
-
include_directories(..)
target_link_libraries(${EXECUTABLE} devcrypto)
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/Exceptions.cpp b/libethcore/Exceptions.cpp
index 2936e9353..c6f35763e 100644
--- a/libethcore/Exceptions.cpp
+++ b/libethcore/Exceptions.cpp
@@ -22,14 +22,17 @@
#include "Exceptions.h"
#include
+using namespace std;
using namespace dev;
using namespace dev::eth;
-const char* InvalidBlockFormat::what() const noexcept { return ("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")").c_str(); }
-const char* UncleInChain::what() const noexcept { return ("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")").c_str(); }
-const char* InvalidTransactionsHash::what() const noexcept { return ("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())).c_str(); }
-const char* InvalidGasLimit::what() const noexcept { return ("Invalid gas limit (provided: " + toString(provided) + " valid:" + toString(valid) + ")").c_str(); }
-const char* InvalidMinGasPrice::what() const noexcept { return ("Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")").c_str(); }
-const char* InvalidNonce::what() const noexcept { return ("Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")").c_str(); }
-const char* InvalidBlockNonce::what() const noexcept { return ("Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")").c_str(); }
+#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str();
+
+const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); }
+const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); }
+const char* InvalidTransactionsHash::what() const noexcept { ETH_RETURN_STRING("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())); }
+const char* InvalidGasLimit::what() const noexcept { ETH_RETURN_STRING("Invalid gas limit (provided: " + toString(provided) + " valid:" + toString(valid) + ")"); }
+const char* InvalidMinGasPrice::what() const noexcept { ETH_RETURN_STRING("Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")"); }
+const char* InvalidNonce::what() const noexcept { ETH_RETURN_STRING("Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")"); }
+const char* InvalidBlockNonce::what() const noexcept { ETH_RETURN_STRING("Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")"); }
diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h
index f9207f795..8a4723696 100644
--- a/libethcore/Exceptions.h
+++ b/libethcore/Exceptions.h
@@ -48,7 +48,7 @@ class InvalidBlockFormat: public dev::Exception { public: InvalidBlockFormat(int
struct InvalidUnclesHash: virtual dev::Exception {};
struct InvalidUncle: virtual dev::Exception {};
struct UncleTooOld: virtual dev::Exception {};
-class UncleInChain: public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block;virtual const char* what() const noexcept; };
+class UncleInChain: public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; };
struct DuplicateUncleNonce: virtual dev::Exception {};
struct InvalidStateRoot: virtual dev::Exception {};
class InvalidTransactionsHash: public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; };
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 0a66a0979..d07bb71f3 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"
@@ -43,7 +43,9 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().ToString() != "best")
{
- BlockDetails d(RLP(it->value().ToString()));
+ string rlpString = it->value().ToString();
+ RLP r(rlpString);
+ BlockDetails d(r);
_out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parent << (cmp == it->key().ToString() ? " BEST" : "") << std::endl;
}
delete it;
@@ -426,7 +428,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)
@@ -434,11 +439,17 @@ void BlockChain::checkConsistency()
h256 h((byte const*)it->key().data(), h256::ConstructFromPointer);
auto dh = details(h);
auto p = dh.parent;
- if (p != h256())
+ if (p != h256() && p != m_genesisHash) // TODO: for some reason the genesis details with the children get squished. not sure why.
{
auto dp = details(p);
- assert(contains(dp.children, h));
- assert(dp.number == dh.number - 1);
+ if (asserts(contains(dp.children, h)))
+ {
+ cnote << "Apparently the database is corrupt. Not much we can do at this stage...";
+ }
+ if (assertsEqual(dp.number, dh.number - 1))
+ {
+ cnote << "Apparently the database is corrupt. Not much we can do at this stage...";
+ }
}
}
delete it;
diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt
index 128dd5999..cb2049886 100644
--- a/libethereum/CMakeLists.txt
+++ b/libethereum/CMakeLists.txt
@@ -6,15 +6,13 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE ethereum)
-# set(CMAKE_INSTALL_PREFIX ../lib)
+file(GLOB HEADERS "*.h")
if(ETH_STATIC)
- add_library(${EXECUTABLE} STATIC ${SRC_LIST})
+ add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
- add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
-file(GLOB HEADERS "*.h")
-
include_directories(..)
target_link_libraries(${EXECUTABLE} evm)
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..5daf67fb9 100644
--- a/libethereum/EthereumHost.cpp
+++ b/libethereum/EthereumHost.cpp
@@ -148,17 +148,19 @@ void EthereumHost::doWork()
{
bool netChange = ensureInitialised();
auto h = m_chain.currentHash();
- maintainTransactions(h);
- maintainBlocks(h);
+ // If we've finished our initial sync (including getting all the blocks into the chain so as to reduce invalid transactions), start trading transactions & blocks
+ if (!isSyncing() && m_chain.isKnown(m_latestBlockSent))
+ {
+ maintainTransactions();
+ maintainBlocks(h);
+ }
// return netChange;
// TODO: Figure out what to do with netChange.
(void)netChange;
}
-void EthereumHost::maintainTransactions(h256 _currentHash)
+void EthereumHost::maintainTransactions()
{
- bool resendAll = (!isSyncing() && m_chain.isKnown(m_latestBlockSent) && _currentHash != m_latestBlockSent);
-
// Send any new transactions.
for (auto const& p: peers())
if (auto ep = p->cap())
@@ -166,14 +168,14 @@ void EthereumHost::maintainTransactions(h256 _currentHash)
bytes b;
unsigned n = 0;
for (auto const& i: m_tq.transactions())
- if ((!m_transactionsSent.count(i.first) && !ep->m_knownTransactions.count(i.first)) || ep->m_requireTransactions || resendAll)
+ if (ep->m_requireTransactions || (!m_transactionsSent.count(i.first) && !ep->m_knownTransactions.count(i.first)))
{
b += i.second;
++n;
m_transactionsSent.insert(i.first);
}
ep->clearKnownTransactions();
-
+
if (n || ep->m_requireTransactions)
{
RLPStream ts;
@@ -186,23 +188,17 @@ void EthereumHost::maintainTransactions(h256 _currentHash)
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)
+ // Send any new blocks.
+ if (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/EthereumHost.h b/libethereum/EthereumHost.h
index a4ccf5383..18ba765aa 100644
--- a/libethereum/EthereumHost.h
+++ b/libethereum/EthereumHost.h
@@ -72,7 +72,7 @@ public:
DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { return !!m_syncer; }
- bool isBanned(h512 _id) const { return !!m_banned.count(_id); }
+ bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); }
private:
/// Session is tell us that we may need (re-)syncing with the peer.
@@ -84,7 +84,7 @@ private:
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
void doWork();
- void maintainTransactions(h256 _currentBlock);
+ void maintainTransactions();
void maintainBlocks(h256 _currentBlock);
/// Get a bunch of needed blocks.
@@ -116,7 +116,7 @@ private:
h256 m_latestBlockSent;
h256Set m_transactionsSent;
- std::set m_banned;
+ std::set m_banned;
};
}
diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp
index 5817aa434..24b400c1d 100644
--- a/libethereum/EthereumPeer.cpp
+++ b/libethereum/EthereumPeer.cpp
@@ -82,7 +82,11 @@ void EthereumPeer::transition(Asking _a, bool _force)
{
clogS(NetMessageSummary) << "Transition!" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : "");
+ if (m_asking == Asking::State && _a != Asking::State)
+ m_requireTransactions = true;
+
RLPStream s;
+
if (_a == Asking::State)
{
if (m_asking == Asking::Nothing)
@@ -288,6 +292,8 @@ void EthereumPeer::attemptSync()
bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
{
+ try
+ {
switch (_id)
{
case StatusPacket:
@@ -322,11 +328,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
}
break;
}
- case GetTransactionsPacket:
- {
- m_requireTransactions = true;
- break;
- }
+ case GetTransactionsPacket: break; // DEPRECATED.
case TransactionsPacket:
{
clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << "entries)";
@@ -509,5 +511,11 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
default:
return false;
}
+ }
+ catch (std::exception const& _e)
+ {
+ clogS(NetWarn) << "Peer causing an exception:" << _e.what() << _r;
+ }
+
return true;
}
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index 61d179ed8..f31683be0 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -54,23 +54,23 @@ bool Executive::setup(bytesConstRef _rlp)
auto nonceReq = m_s.transactionsFrom(m_sender);
if (m_t.nonce != nonceReq)
{
- clog(StateChat) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce;
+ clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce;
BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce));
}
// Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going.
if (m_t.gasPrice < m_s.m_currentBlock.minGasPrice)
{
- clog(StateChat) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice;
+ clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice;
BOOST_THROW_EXCEPTION(GasPriceTooLow());
}
// Check gas cost is enough.
- u256 gasCost = m_t.data.size() * c_txDataGas + c_txGas;
+ u256 gasCost = u256(m_t.data.size()) * FeeStructure::c_txDataGas + FeeStructure::c_txGas;
if (m_t.gas < gasCost)
{
- clog(StateChat) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas;
+ clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas;
BOOST_THROW_EXCEPTION(OutOfGas());
}
@@ -79,14 +79,14 @@ bool Executive::setup(bytesConstRef _rlp)
// Avoid unaffordable transactions.
if (m_s.balance(m_sender) < cost)
{
- clog(StateChat) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender);
+ clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender);
BOOST_THROW_EXCEPTION(NotEnoughCash());
}
u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + m_t.gas > m_s.m_currentBlock.gasLimit)
{
- clog(StateChat) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas;
+ clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas;
BOOST_THROW_EXCEPTION(BlockGasLimitReached());
}
@@ -94,7 +94,7 @@ bool Executive::setup(bytesConstRef _rlp)
m_s.noteSending(m_sender);
// Pay...
-// cnote << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas << "gas at" << formatBalance(m_t.gasPrice) << ")";
+ clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas << "gas at" << formatBalance(m_t.gasPrice) << ")";
m_s.subBalance(m_sender, cost);
if (m_ms)
@@ -158,7 +158,7 @@ OnOpFunc Executive::simpleTrace()
for (auto const& i: ext.state().storage(ext.myAddress))
o << showbase << hex << i.first << ": " << i.second << endl;
dev::LogOutputStream(true) << o.str();
- dev::LogOutputStream(false) << " | " << dec << ext.level << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]";
+ dev::LogOutputStream(false) << " | " << dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]";
};
}
diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h
index 3b4b7161f..612164d13 100644
--- a/libethereum/ExtVM.h
+++ b/libethereum/ExtVM.h
@@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace
{
public:
/// Full constructor.
- ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _level = 0):
- ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock), level(_level), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms)
+ ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _depth = 0):
+ ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms)
{
m_s.ensureCached(_myAddress, true, true);
}
@@ -61,7 +61,7 @@ public:
m_s.noteSending(myAddress);
if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1);
- auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1);
+ auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
@@ -72,7 +72,7 @@ public:
{
if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1);
- auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1);
+ auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
@@ -100,9 +100,6 @@ public:
State& state() const { return m_s; }
- /// @note not a part of the main API; just for use by tracing/debug stuff.
- unsigned level = 0;
-
private:
State& m_s; ///< A reference to the base state.
std::map m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.
diff --git a/libethereum/Interface.h b/libethereum/Interface.h
index 7ae650590..6a32e81c4 100644
--- a/libethereum/Interface.h
+++ b/libethereum/Interface.h
@@ -123,7 +123,7 @@ public:
virtual Addresses addresses(int _block) const = 0;
/// Get the fee associated for a transaction with the given data.
- static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return c_txDataGas * _dataCount + c_txGas + _gas; }
+ static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return FeeStructure::c_txDataGas * u256(_dataCount) + FeeStructure::c_txGas + _gas; }
/// Get the remaining gas limit in this block.
virtual u256 gasLimitRemaining() const = 0;
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 047b9dcd5..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"
@@ -75,7 +74,9 @@ void ripemd160Code(bytesConstRef _in, bytesRef _out)
{
h256 ret;
ripemd160(_in, bytesRef(ret.data(), 32));
- memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret)));
+ memset(_out.data(), 0, std::min(12, _out.size()));
+ if (_out.size() > 12)
+ memcpy(_out.data() + 12, &ret, min(_out.size() - 12, sizeof(ret)));
}
const std::map State::c_precompiled =
@@ -835,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();
@@ -1284,8 +1285,8 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)
{
auto it = _s.m_cache.find(i);
AddressState* cache = it != _s.m_cache.end() ? &it->second : nullptr;
- auto rlpString = trie.at(i);
- RLP r(dtr.count(i) ? rlpString : "");
+ string rlpString = dtr.count(i) ? trie.at(i) : "";
+ RLP r(rlpString);
assert(cache || r);
if (cache && !cache->isAlive())
@@ -1298,7 +1299,8 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)
stringstream contout;
- if ((!cache || cache->codeBearing()) && (!r || r[3].toHash() != EmptySHA3))
+ /// For POC6, 3rd value of account is code and will be empty if code is not present.
+ if ((cache && cache->codeBearing()) || (!cache && r && !r[3].isEmpty()))
{
std::map mem;
std::set back;
diff --git a/libethereum/State.h b/libethereum/State.h
index a28d8155c..5552ba454 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -29,7 +29,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include "TransactionQueue.h"
@@ -40,15 +40,16 @@
namespace dev
{
-namespace test{ class FakeExtVM;}
+namespace test{ class FakeExtVM; class FakeState;}
namespace eth
{
class BlockChain;
-struct StateChat: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 4; };
+struct StateChat: public LogChannel { static const char* name() { return "-S-"; } static const int verbosity = 4; };
struct StateTrace: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 7; };
+struct StateDetail: public LogChannel { static const char* name() { return "/S/"; } static const int verbosity = 14; };
struct TransactionReceipt
{
@@ -84,6 +85,7 @@ class State
{
friend class ExtVM;
friend class test::FakeExtVM;
+ friend class test::FakeState;
friend class Executive;
public:
@@ -321,7 +323,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/CMakeLists.txt b/libevm/CMakeLists.txt
index f19119f83..0c31a9fc3 100644
--- a/libevm/CMakeLists.txt
+++ b/libevm/CMakeLists.txt
@@ -6,15 +6,13 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE evm)
-# set(CMAKE_INSTALL_PREFIX ../lib)
+file(GLOB HEADERS "*.h")
if(ETH_STATIC)
- add_library(${EXECUTABLE} STATIC ${SRC_LIST})
+ add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
- add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
-file(GLOB HEADERS "*.h")
-
include_directories(..)
target_link_libraries(${EXECUTABLE} ethcore)
diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp
index 7c938417a..da189d899 100644
--- a/libevm/ExtVMFace.cpp
+++ b/libevm/ExtVMFace.cpp
@@ -25,7 +25,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
-ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock):
+ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth):
myAddress(_myAddress),
caller(_caller),
origin(_origin),
@@ -34,6 +34,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256
data(_data),
code(_code),
previousBlock(_previousBlock),
- currentBlock(_currentBlock)
+ currentBlock(_currentBlock),
+ depth(_depth)
{}
diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h
index f78cb82cb..1b0f9eaf5 100644
--- a/libevm/ExtVMFace.h
+++ b/libevm/ExtVMFace.h
@@ -54,7 +54,7 @@ public:
ExtVMFace() {}
/// Full constructor.
- ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock);
+ ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth);
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(unsigned)_n] : 0; }
@@ -99,6 +99,7 @@ public:
BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information.
std::set suicides; ///< Any accounts that have suicided.
+ unsigned depth; ///< Depth of the present call.
};
}
diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp
index d29b9fef9..aeeb19e27 100644
--- a/libevm/FeeStructure.cpp
+++ b/libevm/FeeStructure.cpp
@@ -16,22 +16,168 @@
*/
/** @file FeeStructure.cpp
* @author Gav Wood
+ * @author Pawel Bylica
* @date 2014
*/
#include "FeeStructure.h"
-using namespace std;
-using namespace dev;
-using namespace dev::eth;
-
-u256 const dev::eth::c_stepGas = 1;
-u256 const dev::eth::c_balanceGas = 20;
-u256 const dev::eth::c_sha3Gas = 20;
-u256 const dev::eth::c_sloadGas = 20;
-u256 const dev::eth::c_sstoreGas = 100;
-u256 const dev::eth::c_createGas = 100;
-u256 const dev::eth::c_callGas = 20;
-u256 const dev::eth::c_memoryGas = 1;
-u256 const dev::eth::c_txDataGas = 5;
-u256 const dev::eth::c_txGas = 500;
+#include
+
+#include "VM.h"
+
+namespace dev
+{
+namespace eth
+{
+
+uint32_t FeeStructure::getInstructionFee(Instruction _inst)
+{
+ switch (_inst)
+ {
+ default:
+ BOOST_THROW_EXCEPTION(BadInstruction());
+
+ case Instruction::STOP:
+ case Instruction::SUICIDE:
+ return 0;
+
+ case Instruction::SSTORE:
+ return c_sstoreGas;
+
+ case Instruction::SLOAD:
+ return c_sloadGas;
+
+ case Instruction::SHA3:
+ return c_sha3Gas;
+
+ case Instruction::BALANCE:
+ return c_sha3Gas;
+
+ case Instruction::CALL:
+ case Instruction::CALLCODE:
+ return c_callGas;
+
+ case Instruction::CREATE:
+ return c_createGas;
+
+ 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:
+ case Instruction::RETURN:
+ case Instruction::MSTORE:
+ case Instruction::MSTORE8:
+ case Instruction::MLOAD:
+ case Instruction::CALLDATACOPY:
+ case Instruction::CODECOPY:
+ case Instruction::EXTCODECOPY:
+ return c_stepGas;
+ }
+}
+
+}
+}
\ No newline at end of file
diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h
index 76be9a398..60a158388 100644
--- a/libevm/FeeStructure.h
+++ b/libevm/FeeStructure.h
@@ -16,28 +16,40 @@
*/
/** @file FeeStructure.h
* @author Gav Wood
+ * @author Pawel Bylica
* @date 2014
*/
#pragma once
-#include
+#include
+
+#include
namespace dev
{
namespace eth
{
-extern u256 const c_stepGas; ///< Once per operation, except for SSTORE, SLOAD, BALANCE, SHA3, CREATE, CALL.
-extern u256 const c_balanceGas; ///< Once per BALANCE operation.
-extern u256 const c_sha3Gas; ///< Once per SHA3 operation.
-extern u256 const c_sloadGas; ///< Once per SLOAD operation.
-extern u256 const c_sstoreGas; ///< Once per non-zero storage element in a CREATE call/transaction. Also, once/twice per SSTORE operation depending on whether the zeroness changes (twice iff it changes from zero; nothing at all if to zero) or doesn't (once).
-extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction.
-extern u256 const c_callGas; ///< Once per CALL operation & message call transaction.
-extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
-extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions.
-extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions.
+enum class Instruction: uint8_t;
+
+struct FeeStructure
+{
+ static uint32_t const c_stepGas = 1; ///< Once per operation, except for SSTORE, SLOAD, BALANCE, SHA3, CREATE, CALL.
+ static uint32_t const c_balanceGas = 20; ///< Once per BALANCE operation.
+ static uint32_t const c_sha3Gas = 20; ///< Once per SHA3 operation.
+ static uint32_t const c_sloadGas = 20; ///< Once per SLOAD operation.
+ static uint32_t const c_sstoreGas = 100; ///< Once per non-zero storage element in a CREATE call/transaction. Also, once/twice per SSTORE operation depending on whether the zeroness changes (twice iff it changes from zero; nothing at all if to zero) or doesn't (once).
+ static uint32_t const c_createGas = 100; ///< Once per CREATE operation & contract-creation transaction.
+ static uint32_t const c_callGas = 20; ///< Once per CALL operation & message call transaction.
+ static uint32_t const c_memoryGas = 1; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
+ static uint32_t const c_txDataGas = 5; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions.
+ static uint32_t const c_txGas = 500; ///< Per transaction. NOTE: Not payable on data of calls between transactions.
+
+ /// Returns step fee of the instruction.
+ /// In case of bad instruction code, throws BadInstruction exception.
+ static uint32_t getInstructionFee(Instruction _inst);
+};
}
}
diff --git a/libevm/VM.h b/libevm/VM.h
index 399df72dd..e97e5c4eb 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -101,30 +101,17 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
Instruction inst = (Instruction)_ext.getCode(m_curPC);
// FEES...
- bigint runGas = c_stepGas;
+ bigint runGas = FeeStructure::getInstructionFee(inst); // throws BadInstruction
bigint newTempSize = m_temp.size();
switch (inst)
{
- case Instruction::STOP:
- runGas = 0;
- break;
-
- case Instruction::SUICIDE:
- runGas = 0;
- break;
case Instruction::SSTORE:
require(2);
if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
- runGas = c_sstoreGas * 2;
+ runGas = FeeStructure::c_sstoreGas * 2;
else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
runGas = 0;
- else
- runGas = c_sstoreGas;
- break;
-
- case Instruction::SLOAD:
- runGas = c_sloadGas;
break;
// These all operate on memory and therefore potentially expand it:
@@ -146,7 +133,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
case Instruction::SHA3:
require(2);
- runGas = c_sha3Gas;
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
break;
case Instruction::CALLDATACOPY:
@@ -161,20 +147,11 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
require(4);
newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]);
break;
-
- case Instruction::BALANCE:
- runGas = c_balanceGas;
- break;
case Instruction::CALL:
- require(7);
- runGas = c_callGas + m_stack[m_stack.size() - 1];
- newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]));
- break;
-
case Instruction::CALLCODE:
require(7);
- runGas = c_callGas + m_stack[m_stack.size() - 1];
+ runGas += m_stack[m_stack.size() - 1];
newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]));
break;
@@ -184,17 +161,14 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
auto inOff = m_stack[m_stack.size() - 2];
auto inSize = m_stack[m_stack.size() - 3];
newTempSize = inOff + inSize;
- runGas = c_createGas;
break;
}
- default:
- break;
}
newTempSize = (newTempSize + 31) / 32 * 32;
if (newTempSize > m_temp.size())
- runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32;
+ runGas += FeeStructure::c_memoryGas * (newTempSize - m_temp.size()) / 32;
if (_onOp)
_onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext);
@@ -567,7 +541,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::JUMP:
require(1);
nextPC = m_stack.back();
- if ((Instruction)_ext.getCode(nextPC) != Instruction::JUMPDEST)
+ if (nextPC && (Instruction)_ext.getCode(nextPC - 1) != Instruction::JUMPDEST)
BOOST_THROW_EXCEPTION(BadJumpDestination());
m_stack.pop_back();
break;
@@ -576,7 +550,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
if (m_stack[m_stack.size() - 2])
{
nextPC = m_stack.back();
- if ((Instruction)_ext.getCode(nextPC) != Instruction::JUMPDEST)
+ if (nextPC && (Instruction)_ext.getCode(nextPC - 1) != Instruction::JUMPDEST)
BOOST_THROW_EXCEPTION(BadJumpDestination());
}
m_stack.pop_back();
@@ -606,6 +580,8 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
if (_ext.balance(_ext.myAddress) >= endowment)
{
+ if (_ext.depth == 1024)
+ BOOST_THROW_EXCEPTION(OutOfGas());
_ext.subBalance(endowment);
m_stack.push_back((u160)_ext.create(endowment, &m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp));
}
@@ -636,6 +612,8 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
if (_ext.balance(_ext.myAddress) >= value)
{
+ if (_ext.depth == 1024)
+ BOOST_THROW_EXCEPTION(OutOfGas());
_ext.subBalance(value);
m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), &gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, Address(), receiveAddress));
}
@@ -665,8 +643,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/libevmface/CMakeLists.txt b/libevmface/CMakeLists.txt
index 212ce825d..874b9e397 100644
--- a/libevmface/CMakeLists.txt
+++ b/libevmface/CMakeLists.txt
@@ -6,15 +6,13 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE evmface)
-# set(CMAKE_INSTALL_PREFIX ../lib)
+file(GLOB HEADERS "*.h")
if(ETH_STATIC)
- add_library(${EXECUTABLE} STATIC ${SRC_LIST})
+ add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
- add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
-file(GLOB HEADERS "*.h")
-
include_directories(..)
target_link_libraries(${EXECUTABLE} devcore)
diff --git a/evmcc/BasicBlock.cpp b/libevmjit/BasicBlock.cpp
similarity index 100%
rename from evmcc/BasicBlock.cpp
rename to libevmjit/BasicBlock.cpp
diff --git a/evmcc/BasicBlock.h b/libevmjit/BasicBlock.h
similarity index 100%
rename from evmcc/BasicBlock.h
rename to libevmjit/BasicBlock.h
diff --git a/evmcc/Compiler.cpp b/libevmjit/Compiler.cpp
similarity index 94%
rename from evmcc/Compiler.cpp
rename to libevmjit/Compiler.cpp
index c2c8376fd..f3e912125 100644
--- a/evmcc/Compiler.cpp
+++ b/libevmjit/Compiler.cpp
@@ -29,7 +29,7 @@ Compiler::Compiler():
Type::init(m_builder.getContext());
}
-void Compiler::createBasicBlocks(const bytes& bytecode)
+void Compiler::createBasicBlocks(bytesConstRef bytecode)
{
std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end
splitPoints.insert(0); // First basic block
@@ -38,9 +38,9 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
std::vector indirectJumpTargets;
boost::dynamic_bitset<> validJumpTargets(bytecode.size());
- for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr)
+ for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr)
{
- ProgramCounter currentPC = curr - bytecode.cbegin();
+ ProgramCounter currentPC = curr - bytecode.begin();
validJumpTargets[currentPC] = 1;
auto inst = static_cast(*curr);
@@ -51,7 +51,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
{
auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1;
auto next = curr + numBytes + 1;
- if (next >= bytecode.cend())
+ if (next >= bytecode.end())
break;
auto nextInst = static_cast(*next);
@@ -67,12 +67,10 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
}
// Create a block for the JUMP target.
- ProgramCounter targetPC = val.convert_to();
- if (targetPC > bytecode.size())
- targetPC = bytecode.size();
+ ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size();
splitPoints.insert(targetPC);
- ProgramCounter jumpPC = (next - bytecode.cbegin());
+ ProgramCounter jumpPC = (next - bytecode.begin());
directJumpTargets[jumpPC] = targetPC;
}
@@ -95,7 +93,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
case Instruction::SUICIDE:
{
// Create a basic block starting at the following instruction.
- if (curr + 1 < bytecode.cend())
+ if (curr + 1 < bytecode.end())
{
splitPoints.insert(currentPC + 1);
}
@@ -130,16 +128,23 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
{
+ if (it->second >= bytecode.size())
+ {
+ // Jumping out of code means STOP
+ m_directJumpTargets[it->first] = m_stopBB;
+ continue;
+ }
+
auto blockIter = basicBlocks.find(it->second);
if (blockIter != basicBlocks.end())
{
- m_directJumpTargets[it->first] = &(blockIter->second);
+ m_directJumpTargets[it->first] = blockIter->second.llvm();
}
else
{
std::cerr << "Bad JUMP at PC " << it->first
<< ": " << it->second << " is not a valid PC\n";
- m_directJumpTargets[it->first] = m_badJumpBlock.get();
+ m_directJumpTargets[it->first] = m_badJumpBlock->llvm();
}
}
@@ -149,7 +154,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
}
}
-std::unique_ptr Compiler::compile(const bytes& bytecode)
+std::unique_ptr Compiler::compile(bytesConstRef bytecode)
{
auto module = std::make_unique("main", m_builder.getContext());
@@ -214,7 +219,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode)
}
-void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock)
+void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock)
{
auto& stack = basicBlock.getStack();
m_builder.SetInsertPoint(basicBlock.llvm());
@@ -567,7 +572,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode,
// 1. this is not the first instruction in the block
// 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH)
// Otherwise generate a indirect jump (a switch).
- BasicBlock* targetBlock = nullptr;
+ llvm::BasicBlock* targetBlock = nullptr;
if (currentPC != basicBlock.begin())
{
auto pairIter = m_directJumpTargets.find(currentPC);
@@ -584,7 +589,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode,
// The target address is computed at compile time,
// just pop it without looking...
stack.pop();
- m_builder.CreateBr(targetBlock->llvm());
+ m_builder.CreateBr(targetBlock);
}
else
{
@@ -606,7 +611,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode,
if (targetBlock)
{
stack.pop();
- m_builder.CreateCondBr(cond, targetBlock->llvm(), nextBasicBlock);
+ m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock);
}
else
{
@@ -923,10 +928,18 @@ void Compiler::linkBasicBlocks()
for (auto it = llvm::po_ext_begin(bb.second.llvm(), visitSet),
end = llvm::po_ext_end(bb.second.llvm(), visitSet); it != end; ++it)
{
- std::cerr << it->getName().str() << std::endl;
+ // TODO: Use logger
+ //std::cerr << it->getName().str() << std::endl;
completePhiNodes(*it);
}
}
+
+ // Remove jump table block if not predecessors
+ if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm()))
+ {
+ m_jumpTableBlock->llvm()->eraseFromParent();
+ m_jumpTableBlock.reset();
+ }
}
void Compiler::dumpBasicBlockGraph(std::ostream& out)
diff --git a/evmcc/Compiler.h b/libevmjit/Compiler.h
similarity index 75%
rename from evmcc/Compiler.h
rename to libevmjit/Compiler.h
index bda154689..8972322ec 100644
--- a/evmcc/Compiler.h
+++ b/libevmjit/Compiler.h
@@ -22,16 +22,16 @@ public:
Compiler();
- std::unique_ptr compile(const bytes& bytecode);
+ std::unique_ptr compile(bytesConstRef bytecode);
void dumpBasicBlockGraph(std::ostream& out);
private:
- void createBasicBlocks(const bytes& bytecode);
+ void createBasicBlocks(bytesConstRef bytecode);
- void compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
+ void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
void linkBasicBlocks();
@@ -46,7 +46,7 @@ private:
/**
* Maps a pc at which there is a JUMP or JUMPI to the target block of the jump.
*/
- std::map m_directJumpTargets;
+ std::map m_directJumpTargets;
/**
* A list of possible blocks to which there may be indirect jumps.
diff --git a/evmcc/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp
similarity index 100%
rename from evmcc/CompilerHelper.cpp
rename to libevmjit/CompilerHelper.cpp
diff --git a/evmcc/CompilerHelper.h b/libevmjit/CompilerHelper.h
similarity index 100%
rename from evmcc/CompilerHelper.h
rename to libevmjit/CompilerHelper.h
diff --git a/evmcc/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp
similarity index 75%
rename from evmcc/ExecutionEngine.cpp
rename to libevmjit/ExecutionEngine.cpp
index 6a494f42a..5390d82dd 100644
--- a/evmcc/ExecutionEngine.cpp
+++ b/libevmjit/ExecutionEngine.cpp
@@ -36,7 +36,7 @@ ExecutionEngine::ExecutionEngine()
extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; }
-int ExecutionEngine::run(std::unique_ptr _module)
+int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtVMFace* _ext)
{
auto module = _module.get(); // Keep ownership of the module in _module
@@ -81,26 +81,28 @@ int ExecutionEngine::run(std::unique_ptr _module)
exec->finalizeObject();
// Create fake ExtVM interface
- auto ext = std::make_unique();
- ext->myAddress = Address(1122334455667788);
- ext->caller = Address(0xfacefacefaceface);
- ext->origin = Address(101010101010101010);
- ext->value = 0xabcd;
- ext->gasPrice = 1002;
- ext->previousBlock.hash = u256(1003);
- ext->currentBlock.coinbaseAddress = Address(1004);
- ext->currentBlock.timestamp = 1005;
- ext->currentBlock.number = 1006;
- ext->currentBlock.difficulty = 1007;
- ext->currentBlock.gasLimit = 1008;
- std::string calldata = "Hello the Beautiful World of Ethereum!";
- ext->data = calldata;
- unsigned char fakecode[] = {0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf};
- ext->code = decltype(ext->code)(fakecode, 8);
+ if (!_ext)
+ {
+ _ext = new ExtVMFace;
+ _ext->myAddress = Address(1122334455667788);
+ _ext->caller = Address(0xfacefacefaceface);
+ _ext->origin = Address(101010101010101010);
+ _ext->value = 0xabcd;
+ _ext->gasPrice = 1002;
+ _ext->previousBlock.hash = u256(1003);
+ _ext->currentBlock.coinbaseAddress = Address(1004);
+ _ext->currentBlock.timestamp = 1005;
+ _ext->currentBlock.number = 1006;
+ _ext->currentBlock.difficulty = 1007;
+ _ext->currentBlock.gasLimit = 1008;
+ std::string calldata = "Hello the Beautiful World of Ethereum!";
+ _ext->data = calldata;
+ unsigned char fakecode[] = {0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf};
+ _ext->code = decltype(_ext->code)(fakecode, 8);
+ }
// Init runtime
- uint64_t gas = 100;
- Runtime runtime(gas, std::move(ext));
+ Runtime runtime(_gas, *_ext);
auto entryFunc = module->getFunction("main");
if (!entryFunc)
@@ -121,11 +123,11 @@ int ExecutionEngine::run(std::unique_ptr _module)
else
returnCode = static_cast(r);
- gas = static_cast(Runtime::getGas());
+ _gas = Runtime::getGas();
if (returnCode == ReturnCode::Return)
{
- auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface
+ returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface
std::cout << "RETURN [ ";
for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it)
diff --git a/evmcc/ExecutionEngine.h b/libevmjit/ExecutionEngine.h
similarity index 57%
rename from evmcc/ExecutionEngine.h
rename to libevmjit/ExecutionEngine.h
index 158df0283..15a4e6ef7 100644
--- a/evmcc/ExecutionEngine.h
+++ b/libevmjit/ExecutionEngine.h
@@ -4,6 +4,7 @@
#include
#include
+#include
namespace dev
{
@@ -17,7 +18,9 @@ class ExecutionEngine
public:
ExecutionEngine();
- int run(std::unique_ptr module);
+ int run(std::unique_ptr module, u256& _gas, ExtVMFace* _ext = nullptr);
+
+ bytes returnData;
};
}
diff --git a/evmcc/Ext.cpp b/libevmjit/Ext.cpp
similarity index 99%
rename from evmcc/Ext.cpp
rename to libevmjit/Ext.cpp
index 5307bc191..5c4bb7c59 100644
--- a/evmcc/Ext.cpp
+++ b/libevmjit/Ext.cpp
@@ -61,7 +61,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder):
m_arg5 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg5");
m_arg6 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg6");
m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7");
- m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8");
+ m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8");
Type* elements[] = {
i256Ty, // i256 address;
diff --git a/evmcc/Ext.h b/libevmjit/Ext.h
similarity index 100%
rename from evmcc/Ext.h
rename to libevmjit/Ext.h
diff --git a/evmcc/GasMeter.cpp b/libevmjit/GasMeter.cpp
similarity index 87%
rename from evmcc/GasMeter.cpp
rename to libevmjit/GasMeter.cpp
index 9c83ba8db..ac7f47d19 100644
--- a/evmcc/GasMeter.cpp
+++ b/libevmjit/GasMeter.cpp
@@ -30,26 +30,26 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure
return 0;
case Instruction::SSTORE:
- return static_cast(c_sstoreGas);
+ return static_cast(FeeStructure::c_sstoreGas);
case Instruction::SLOAD:
- return static_cast(c_sloadGas);
+ return static_cast(FeeStructure::c_sloadGas);
case Instruction::SHA3:
- return static_cast(c_sha3Gas);
+ return static_cast(FeeStructure::c_sha3Gas);
case Instruction::BALANCE:
- return static_cast(c_sha3Gas);
+ return static_cast(FeeStructure::c_sha3Gas);
case Instruction::CALL:
case Instruction::CALLCODE:
- return static_cast(c_callGas);
+ return static_cast(FeeStructure::c_callGas);
case Instruction::CREATE:
- return static_cast(c_createGas);
+ return static_cast(FeeStructure::c_createGas);
default: // Assumes instruction code is valid
- return static_cast(c_stepGas);
+ return static_cast(FeeStructure::c_stepGas);
}
}
@@ -134,7 +134,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu
{
assert(!m_checkCall); // Everything should've been commited before
- static const auto sstoreCost = static_cast(c_sstoreGas);
+ static const auto sstoreCost = static_cast(FeeStructure::c_sstoreGas);
// [ADD] if oldValue == 0 and newValue != 0 => 2*cost
// [DEL] if oldValue != 0 and newValue == 0 => 0
@@ -165,19 +165,21 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
// If any uncommited block
if (m_checkCall)
{
- if (m_blockCost == 0 && !_additionalCost) // Do not check 0
+ if (m_blockCost == 0) // Do not check 0
{
m_checkCall->eraseFromParent(); // Remove the gas check call
+ m_checkCall = nullptr;
return;
}
- llvm::Value* cost = Constant::get(m_blockCost);
- if (_additionalCost)
- cost = m_builder.CreateAdd(cost, _additionalCost);
-
- m_checkCall->setArgOperand(0, cost); // Update block cost in gas check call
+ m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call
m_checkCall = nullptr; // End cost-block
m_blockCost = 0;
+
+ if (_additionalCost)
+ {
+ m_builder.CreateCall(m_gasCheckFunc, _additionalCost);
+ }
}
assert(m_blockCost == 0);
}
@@ -185,7 +187,7 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder)
{
// Memory uses other builder, but that can be changes later
- auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost");
+ auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(FeeStructure::c_memoryGas)), "memcost");
_builder.CreateCall(m_gasCheckFunc, cost);
}
diff --git a/evmcc/GasMeter.h b/libevmjit/GasMeter.h
similarity index 100%
rename from evmcc/GasMeter.h
rename to libevmjit/GasMeter.h
diff --git a/evmcc/Memory.cpp b/libevmjit/Memory.cpp
similarity index 100%
rename from evmcc/Memory.cpp
rename to libevmjit/Memory.cpp
diff --git a/evmcc/Memory.h b/libevmjit/Memory.h
similarity index 100%
rename from evmcc/Memory.h
rename to libevmjit/Memory.h
diff --git a/evmcc/Runtime.cpp b/libevmjit/Runtime.cpp
similarity index 81%
rename from evmcc/Runtime.cpp
rename to libevmjit/Runtime.cpp
index d85f484b3..448d25f92 100644
--- a/evmcc/Runtime.cpp
+++ b/libevmjit/Runtime.cpp
@@ -19,8 +19,8 @@ extern "C"
EXPORT i256 gas;
}
-Runtime::Runtime(u256 _gas, std::unique_ptr _ext):
- m_ext(std::move(_ext))
+Runtime::Runtime(u256 _gas, ExtVMFace& _ext):
+ m_ext(_ext)
{
assert(!g_runtime);
g_runtime = this;
@@ -44,7 +44,7 @@ MemoryImpl& Runtime::getMemory()
ExtVMFace& Runtime::getExt()
{
- return *g_runtime->m_ext;
+ return g_runtime->m_ext;
}
u256 Runtime::getGas()
diff --git a/evmcc/Runtime.h b/libevmjit/Runtime.h
similarity index 86%
rename from evmcc/Runtime.h
rename to libevmjit/Runtime.h
index 0312e305b..165f47e06 100644
--- a/evmcc/Runtime.h
+++ b/libevmjit/Runtime.h
@@ -27,7 +27,7 @@ using MemoryImpl = bytes;
class Runtime
{
public:
- Runtime(u256 _gas, std::unique_ptr _ext);
+ Runtime(u256 _gas, ExtVMFace& _ext);
~Runtime();
Runtime(const Runtime&) = delete;
@@ -41,7 +41,7 @@ public:
private:
StackImpl m_stack;
MemoryImpl m_memory;
- std::unique_ptr m_ext;
+ ExtVMFace& m_ext;
};
}
diff --git a/evmcc/Type.cpp b/libevmjit/Type.cpp
similarity index 100%
rename from evmcc/Type.cpp
rename to libevmjit/Type.cpp
diff --git a/evmcc/Type.h b/libevmjit/Type.h
similarity index 100%
rename from evmcc/Type.h
rename to libevmjit/Type.h
diff --git a/evmcc/Utils.cpp b/libevmjit/Utils.cpp
similarity index 100%
rename from evmcc/Utils.cpp
rename to libevmjit/Utils.cpp
diff --git a/evmcc/Utils.h b/libevmjit/Utils.h
similarity index 100%
rename from evmcc/Utils.h
rename to libevmjit/Utils.h
diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp
new file mode 100644
index 000000000..6b8b3e38b
--- /dev/null
+++ b/libevmjit/VM.cpp
@@ -0,0 +1,36 @@
+
+#include "VM.h"
+
+#include
+
+#include "ExecutionEngine.h"
+#include "Compiler.h"
+
+namespace dev
+{
+namespace eth
+{
+namespace jit
+{
+
+bytes VM::go(ExtVMFace& _ext)
+{
+ auto module = Compiler().compile(_ext.code);
+
+ ExecutionEngine engine;
+ auto exitCode = engine.run(std::move(module), m_gas, &_ext);
+
+ switch (exitCode)
+ {
+ case 101:
+ BOOST_THROW_EXCEPTION(BadJumpDestination());
+ case 102:
+ BOOST_THROW_EXCEPTION(OutOfGas());
+ }
+
+ return std::move(engine.returnData);
+}
+
+}
+}
+}
diff --git a/libevmjit/VM.h b/libevmjit/VM.h
new file mode 100644
index 000000000..3e7884b10
--- /dev/null
+++ b/libevmjit/VM.h
@@ -0,0 +1,32 @@
+
+#pragma once
+
+#include
+#include
+
+namespace dev
+{
+namespace eth
+{
+namespace jit
+{
+
+class VM
+{
+public:
+ /// Construct VM object.
+ explicit VM(u256 _gas = 0): m_gas(_gas) {}
+
+ void reset(u256 _gas = 0) { m_gas = _gas; }
+
+ bytes go(ExtVMFace& _ext);
+
+ u256 gas() const { return m_gas; }
+
+private:
+ u256 m_gas = 0;
+};
+
+}
+}
+}
diff --git a/liblll/Assembly.cpp b/liblll/Assembly.cpp
index 695c9ffab..c26a9a98e 100644
--- a/liblll/Assembly.cpp
+++ b/liblll/Assembly.cpp
@@ -413,8 +413,8 @@ bytes Assembly::assemble() const
break;
}
case Tag:
- tagPos[(unsigned)i.m_data] = ret.size();
ret.push_back((byte)Instruction::JUMPDEST);
+ tagPos[(unsigned)i.m_data] = ret.size();
break;
default:;
}
diff --git a/liblll/CMakeLists.txt b/liblll/CMakeLists.txt
index 7746613ec..cb50cc36e 100644
--- a/liblll/CMakeLists.txt
+++ b/liblll/CMakeLists.txt
@@ -6,15 +6,13 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE lll)
-# set(CMAKE_INSTALL_PREFIX ../lib)
+file(GLOB HEADERS "*.h")
if(ETH_STATIC)
- add_library(${EXECUTABLE} STATIC ${SRC_LIST})
+ add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
- add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
-file(GLOB HEADERS "*.h")
-
include_directories(..)
target_link_libraries(${EXECUTABLE} evmface)
diff --git a/libp2p/CMakeLists.txt b/libp2p/CMakeLists.txt
index ab852fc57..9e20fd99f 100644
--- a/libp2p/CMakeLists.txt
+++ b/libp2p/CMakeLists.txt
@@ -6,17 +6,16 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE p2p)
-# set(CMAKE_INSTALL_PREFIX ../lib)
+file(GLOB HEADERS "*.h")
if(ETH_STATIC)
- add_library(${EXECUTABLE} STATIC ${SRC_LIST})
+ add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
- add_library(${EXECUTABLE} SHARED ${SRC_LIST})
+ add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
-file(GLOB HEADERS "*.h")
-
include_directories(..)
+target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} secp256k1)
if(MINIUPNPC_LS)
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 895b76404..7c2c61156 100644
--- a/libp2p/Common.h
+++ b/libp2p/Common.h
@@ -44,6 +44,8 @@ class RLPStream;
namespace p2p
{
+using NodeId = h512;
+
bool isPrivateAddress(bi::address const& _addressToCheck);
class UPnP;
@@ -82,11 +84,30 @@ enum DisconnectReason
TooManyPeers,
DuplicatePeer,
IncompatibleProtocol,
- InvalidIdentity,
+ NullIdentity,
ClientQuit,
- UserReason = 0x10
+ UnexpectedIdentity,
+ 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);
@@ -96,6 +117,7 @@ typedef std::vector CapDescs;
struct PeerInfo
{
+ NodeId id;
std::string clientVersion;
std::string host;
unsigned short port;
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index 05fa81f4c..ea89b5613 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -63,11 +63,10 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
m_netPrefs(_n),
m_acceptor(m_ioService),
m_socket(m_ioService),
- m_id(h512::random())
+ m_key(KeyPair::create())
{
populateAddresses();
- m_lastPeersRequest = chrono::steady_clock::time_point::min();
- clog(NetNote) << "Id:" << m_id.abridged();
+ clog(NetNote) << "Id:" << id().abridged();
if (_start)
start();
}
@@ -109,11 +108,10 @@ void Host::start()
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
ensureAccepting();
- m_incomingPeers.clear();
- m_freePeers.clear();
+ 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:" << m_id.abridged();
+ clog(NetNote) << "Id:" << id().abridged();
for (auto const& h: m_capabilities)
h.second->onStarting();
@@ -144,14 +142,20 @@ void Host::stop()
unsigned Host::protocolVersion() const
{
- return 1;
+ return 2;
}
void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps)
{
+ if (!_s->m_node || !_s->m_node->id)
{
- Guard l(x_peers);
- m_peers[_s->m_id] = _s;
+ cwarn << "Attempting to register a peer without node information!";
+ return;
+ }
+
+ {
+ RecursiveGuard l(x_peers);
+ m_peers[_s->m_node->id] = _s;
}
unsigned o = (unsigned)UserPacket;
for (auto const& i: _caps)
@@ -167,7 +171,7 @@ void Host::disconnectPeers()
for (unsigned n = 0;; n = 0)
{
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
for (auto i: m_peers)
if (auto p = i.second.lock())
{
@@ -182,6 +186,7 @@ void Host::disconnectPeers()
}
delete m_upnp;
+ m_upnp = nullptr;
}
void Host::seal(bytes& _b)
@@ -210,7 +215,10 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
if (m_upnp && m_upnp->isValid() && m_peerAddresses.size())
{
clog(NetNote) << "External addr:" << m_upnp->externalIP();
- int p = m_upnp->addRedirect(m_peerAddresses[0].to_string().c_str(), m_listenPort);
+ int p;
+ for (auto const& addr : m_peerAddresses)
+ if ((p = m_upnp->addRedirect(addr.to_string().c_str(), m_listenPort)))
+ break;
if (p)
clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << ".";
else
@@ -226,7 +234,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
else
{
m_public = bi::tcp::endpoint(bi::address::from_string(_publicAddress.empty() ? eip : _publicAddress), (unsigned short)p);
- m_addresses.push_back(m_public.address().to_v4());
+ m_addresses.push_back(m_public.address());
}
}
else
@@ -235,7 +243,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
m_public = bi::tcp::endpoint(_publicAddress.size() ? bi::address::from_string(_publicAddress)
: m_peerAddresses.size() ? m_peerAddresses[0]
: bi::address(), m_listenPort);
- m_addresses.push_back(m_public.address().to_v4());
+ m_addresses.push_back(m_public.address());
}
}
@@ -308,33 +316,107 @@ void Host::populateAddresses()
clog(NetNote) << "Couldn't resolve: " << host;
}
}
+ else if (ifa->ifa_addr->sa_family == AF_INET6)
+ {
+ char host[NI_MAXHOST];
+ if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
+ continue;
+ try
+ {
+ auto it = r.resolve({host, "30303"});
+ bi::tcp::endpoint ep = it->endpoint();
+ bi::address ad = ep.address();
+ m_addresses.push_back(ad.to_v6());
+ bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
+ if (!isLocal)
+ m_peerAddresses.push_back(ad);
+ clog(NetNote) << "Address: " << host << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
+ }
+ catch (...)
+ {
+ clog(NetNote) << "Couldn't resolve: " << host;
+ }
+ }
}
freeifaddrs(ifaddr);
#endif
}
-std::map Host::potentialPeers()
+shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId)
{
- std::map ret;
- if (!m_public.address().is_unspecified())
- ret.insert(make_pair(m_id, m_public));
- Guard l(x_peers);
- for (auto i: m_peers)
- if (auto j = i.second.lock())
- {
- auto ep = j->endpoint();
-// cnote << "Checking potential peer" << j->m_listenPort << j->endpoint() << isPrivateAddress(ep.address()) << ep.port() << j->m_id.abridged();
- // Skip peers with a listen port of zero or are on a private network
- bool peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_netPrefs.localNetworking));
- if (!peerOnNet && m_incomingPeers.count(j->m_id))
+ 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)
{
- ep = m_incomingPeers.at(j->m_id).first;
- peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_netPrefs.localNetworking));
+ _oldId = n.second->id;
+ break;
}
- if (peerOnNet && ep.port() && j->m_id)
- ret.insert(make_pair(i.first, ep));
+
+ unsigned i;
+ if (!m_nodes.count(_id))
+ {
+ if (m_nodes.count(_oldId))
+ {
+ i = m_nodes[_oldId]->index;
+ m_nodes.erase(_oldId);
+ m_nodesList[i] = _id;
+ }
+ else
+ {
+ i = m_nodesList.size();
+ m_nodesList.push_back(_id);
}
+ m_nodes[_id] = make_shared();
+ m_nodes[_id]->id = _id;
+ m_nodes[_id]->index = i;
+ m_nodes[_id]->idOrigin = _o;
+ }
+ else
+ {
+ 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)
+ m_ready += i;
+ else
+ m_ready -= i;
+ if (!_a.port() || (isPrivateAddress(_a.address()) && !m_netPrefs.localNetworking))
+ m_private += i;
+ else
+ m_private -= i;
+
+ cnote << m_nodes[_id]->index << ":" << m_ready;
+
+ m_hadNewNodes = true;
+
+ return m_nodes[_id];
+}
+
+Nodes Host::potentialPeers(RangeMask const& _known)
+{
+ RecursiveGuard l(x_peers);
+ Nodes ret;
+
+ auto ns = (m_netPrefs.localNetworking ? _known : (m_private + _known)).inverted();
+ for (auto i: ns)
+ ret.push_back(*m_nodes[m_nodesList[i]]);
return ret;
}
@@ -355,7 +437,7 @@ void Host::ensureAccepting()
} catch (...){}
bi::address remoteAddress = m_socket.remote_endpoint().address();
// Port defaults to 0 - we let the hello tell us which port the peer listens to
- auto p = std::make_shared(this, std::move(m_socket), remoteAddress);
+ auto p = std::make_shared(this, std::move(m_socket), bi::tcp::endpoint(remoteAddress, 0));
p->start();
}
catch (Exception const& _e)
@@ -411,26 +493,15 @@ void Host::connect(std::string const& _addr, unsigned short _port) noexcept
void Host::connect(bi::tcp::endpoint const& _ep)
{
- clog(NetConnect) << "Attempting connection to " << _ep;
+ clog(NetConnect) << "Attempting single-shot connection to " << _ep;
bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
s->async_connect(_ep, [=](boost::system::error_code const& ec)
{
if (ec)
- {
clog(NetConnect) << "Connection refused to " << _ep << " (" << ec.message() << ")";
- for (auto i = m_incomingPeers.begin(); i != m_incomingPeers.end(); ++i)
- if (i->second.first == _ep && i->second.second < 3)
- {
- m_freePeers.push_back(i->first);
- goto OK;
- }
- // for-else
- clog(NetConnect) << "Giving up.";
- OK:;
- }
else
{
- auto p = make_shared(this, std::move(*s), _ep.address(), _ep.port());
+ auto p = make_shared(this, std::move(*s), _ep);
clog(NetConnect) << "Connected to " << _ep;
p->start();
}
@@ -438,9 +509,36 @@ void Host::connect(bi::tcp::endpoint const& _ep)
});
}
-bool Host::havePeer(h512 _id) const
+void Node::connect(Host* _h)
+{
+ 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)
+ {
+ if (ec)
+ {
+ clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")";
+ lastDisconnect = TCPError;
+ lastAttempted = std::chrono::system_clock::now();
+ _h->m_ready += index;
+ }
+ else
+ {
+ clog(NetConnect) << "Connected to" << id.abridged() << "@" << address;
+ 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();
+ }
+ delete s;
+ });
+}
+
+bool Host::havePeer(NodeId _id) const
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
// Remove dead peers from list.
for (auto i = m_peers.begin(); i != m_peers.end();)
@@ -452,43 +550,67 @@ bool Host::havePeer(h512 _id) const
return !!m_peers.count(_id);
}
+unsigned Node::fallbackSeconds() const
+{
+ 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()
{
- Guard l(x_peers);
- while (m_peers.size() < m_idealPeerCount)
+ RecursiveGuard l(x_peers);
+ int morePeers = (int)m_idealPeerCount - m_peers.size();
+ if (morePeers > 0)
{
- if (m_freePeers.empty())
- {
- if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
+ auto toTry = m_ready;
+ if (!m_netPrefs.localNetworking)
+ toTry -= m_private;
+ set ns;
+ for (auto i: toTry)
+ if (m_nodes[m_nodesList[i]]->shouldReconnect())
+ ns.insert(*m_nodes[m_nodesList[i]]);
+
+ if (ns.size())
+ for (Node const& i: ns)
{
- 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();
+ m_nodes[i.id]->connect(this);
+ if (!--morePeers)
+ return;
}
-
- if (!m_accepting)
- ensureAccepting();
-
- break;
+ else
+ {
+ ensureAccepting();
+ for (auto const& i: m_peers)
+ if (auto p = i.second.lock())
+ p->ensureNodesRequested();
}
-
- auto x = time(0) % m_freePeers.size();
- m_incomingPeers[m_freePeers[x]].second++;
- if (!m_peers.count(m_freePeers[x]))
- connect(m_incomingPeers[m_freePeers[x]].first);
- m_freePeers.erase(m_freePeers.begin() + x);
}
}
void Host::prunePeers()
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
// We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there.
for (unsigned old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
while (m_peers.size() > m_idealPeerCount)
@@ -502,7 +624,7 @@ void Host::prunePeers()
if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
{
++agedPeers;
- if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect))) // kill older ones
+ if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones
worst = p;
}
if (!worst || agedPeers <= m_idealPeerCount)
@@ -520,10 +642,12 @@ void Host::prunePeers()
std::vector Host::peers(bool _updatePing) const
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
if (_updatePing)
+ {
const_cast(this)->pingAll();
- this_thread::sleep_for(chrono::milliseconds(200));
+ this_thread::sleep_for(chrono::milliseconds(200));
+ }
std::vector ret;
for (auto& i: m_peers)
if (auto j = i.second.lock())
@@ -536,41 +660,116 @@ 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();
}
void Host::pingAll()
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
for (auto& i: m_peers)
if (auto j = i.second.lock())
j->ping();
+ m_lastPing = chrono::steady_clock::now();
}
-bytes Host::savePeers() const
+bytes Host::saveNodes() const
{
- Guard l(x_peers);
- RLPStream ret;
- int n = 0;
- for (auto& i: m_peers)
- if (auto p = i.second.lock())
- if (p->m_socket.is_open() && p->endpoint().port())
+ RLPStream nodes;
+ int count = 0;
+ {
+ RecursiveGuard l(x_peers);
+ for (auto const& i: m_nodes)
+ {
+ Node const& n = *(i.second);
+ // 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()))
{
- ret.appendList(3) << p->endpoint().address().to_v4().to_bytes() << p->endpoint().port() << p->m_id;
- n++;
+ nodes.appendList(10);
+ if (n.address.address().is_v4())
+ nodes << n.address.address().to_v4().to_bytes();
+ else
+ nodes << n.address.address().to_v6().to_bytes();
+ 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 << (unsigned)n.lastDisconnect << n.score << n.rating;
+ count++;
}
- return RLPStream(n).appendRaw(ret.out(), n).out();
+ }
+ }
+ RLPStream ret(3);
+ ret << 0 << m_key.secret();
+ ret.appendList(count).appendRaw(nodes.out(), count);
+ return ret.out();
}
-void Host::restorePeers(bytesConstRef _b)
+void Host::restoreNodes(bytesConstRef _b)
{
- for (auto i: RLP(_b))
- {
- auto k = (h512)i[2];
- if (!m_incomingPeers.count(k))
+ RecursiveGuard l(x_peers);
+ RLP r(_b);
+ if (r.itemCount() > 0 && r[0].isInt())
+ 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;
+ if (i[0].itemCount() == 4)
+ ep = bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt());
+ else
+ ep = bi::tcp::endpoint(bi::address_v6(i[0].toArray()), i[1].toInt());
+ auto id = (NodeId)i[2];
+ if (!m_nodes.count(id))
+ {
+ auto o = (Origin)i[3].toInt();
+ auto n = noteNode(id, ep, o, true);
+ 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 = (DisconnectReason)i[7].toInt();
+ n->score = (int)i[8].toInt();
+ n->rating = (int)i[9].toInt();
+ }
+ }
+ }
+ default:;
+ }
+ else
+ for (auto i: r)
{
- m_incomingPeers.insert(make_pair(k, make_pair(bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()), 0)));
- m_freePeers.push_back(k);
+ auto id = (NodeId)i[2];
+ if (!m_nodes.count(id))
+ {
+ bi::tcp::endpoint ep;
+ if (i[0].itemCount() == 4)
+ ep = bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt());
+ else
+ ep = bi::tcp::endpoint(bi::address_v6(i[0].toArray()), i[1].toInt());
+ auto n = noteNode(id, ep, Origin::Self, true);
+ }
}
- }
}
diff --git a/libp2p/Host.h b/libp2p/Host.h
index b4ba9c2d4..c981edc29 100644
--- a/libp2p/Host.h
+++ b/libp2p/Host.h
@@ -28,8 +28,11 @@
#include
#include
#include
+#include
#include
#include
+#include
+#include
#include "HostCapability.h"
#include "Common.h"
namespace ba = boost::asio;
@@ -43,6 +46,63 @@ class RLPStream;
namespace p2p
{
+class Host;
+
+enum class Origin
+{
+ Unknown,
+ Self,
+ SelfThird,
+ PerfectThird,
+ Perfect,
+};
+
+struct Node
+{
+ NodeId id; ///< Their id/public key.
+ unsigned index; ///< Index into m_nodesList
+ 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;
+ DisconnectReason lastDisconnect = NoDisconnect; ///< Reason for disconnect that happened last.
+
+ Origin idOrigin = Origin::Unknown; ///< How did we get to know this node's id?
+
+ 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 (isOffline() != _n.isOffline())
+ return isOffline();
+ else if (isOffline())
+ if (lastAttempted == _n.lastAttempted)
+ return failedAttempts < _n.failedAttempts;
+ else
+ return lastAttempted < _n.lastAttempted;
+ else
+ if (score == _n.score)
+ if (rating == _n.rating)
+ return failedAttempts < _n.failedAttempts;
+ else
+ return rating < _n.rating;
+ else
+ return score < _n.score;
+ }
+
+ void connect(Host* _h);
+};
+
+using Nodes = std::vector;
+
struct NetworkPreferences
{
NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), publicIP(i), upnp(u), localNetworking(l) {}
@@ -61,6 +121,7 @@ class Host: public Worker
{
friend class Session;
friend class HostCapabilityFace;
+ friend struct Node;
public:
/// Start server, listening for connections on the given port.
@@ -88,7 +149,7 @@ public:
void connect(bi::tcp::endpoint const& _ep);
/// @returns true iff we have the a peer of the given id.
- bool havePeer(h512 _id) const;
+ bool havePeer(NodeId _id) const;
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
@@ -97,7 +158,7 @@ public:
std::vector peers(bool _updatePing = false) const;
/// Get number of peers connected; equivalent to, but faster than, peers().size().
- size_t peerCount() const { Guard l(x_peers); return m_peers.size(); }
+ size_t peerCount() const { RecursiveGuard l(x_peers); return m_peers.size(); }
/// Ping the peers, to update the latency information.
void pingAll();
@@ -106,10 +167,12 @@ public:
unsigned short listenPort() const { return m_public.port(); }
/// Serialise the set of known peers.
- bytes savePeers() const;
+ bytes saveNodes() const;
/// Deserialise the data and populate the set of known peers.
- void restorePeers(bytesConstRef _b);
+ 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(); }
@@ -117,14 +180,13 @@ public:
void stop();
bool isStarted() const { return isWorking(); }
- h512 id() const { return m_id; }
+ NodeId id() const { return m_key.pub(); }
void registerPeer(std::shared_ptr _s, CapDescs const& _caps);
-private:
- /// Called when the session has provided us with a new peer we can connect to.
- void noteNewPeers() {}
+ std::shared_ptr node(NodeId _id) const { if (m_nodes.count(_id)) return m_nodes.at(_id); return std::shared_ptr(); }
+private:
void seal(bytes& _b);
void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp);
@@ -138,36 +200,52 @@ private:
/// This won't touch alter the blockchain.
virtual void doWork();
- std::map potentialPeers();
+ std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = h256());
+ Nodes potentialPeers(RangeMask const& _known);
+
+ std::string m_clientVersion; ///< Our version string.
+
+ NetworkPreferences m_netPrefs; ///< Network settings.
+
+ static const int NetworkStopped = -1; ///< The value meaning we're not actually listening.
+ int m_listenPort = NetworkStopped; ///< What port are we listening on?
+
+ ba::io_service m_ioService; ///< IOService for network stuff.
+ bi::tcp::acceptor m_acceptor; ///< Listening acceptor.
+ bi::tcp::socket m_socket; ///< Listening socket.
+
+ UPnP* m_upnp = nullptr; ///< UPnP helper.
+ bi::tcp::endpoint m_public; ///< Our public listening endpoint.
+ KeyPair m_key; ///< Our unique ID.
- std::string m_clientVersion;
+ bool m_hadNewNodes = false;
- NetworkPreferences m_netPrefs;
+ mutable RecursiveMutex x_peers;
- static const int NetworkStopped = -1;
- int m_listenPort = NetworkStopped;
+ /// The nodes to which we are currently connected.
+ /// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
+ mutable std::map> m_peers;
- ba::io_service m_ioService;
- bi::tcp::acceptor m_acceptor;
- bi::tcp::socket m_socket;
+ /// Nodes to which we may connect (or to which we have connected).
+ /// TODO: does this need a lock?
+ std::map > m_nodes;
- UPnP* m_upnp = nullptr;
- bi::tcp::endpoint m_public;
- h512 m_id;
+ /// A list of node IDs. This contains every index from m_nodes; the order is guaranteed to remain the same.
+ std::vector m_nodesList;
- mutable std::mutex x_peers;
- mutable std::map> m_peers; // mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
+ 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::map> m_incomingPeers; // TODO: does this need a lock?
- std::vector m_freePeers;
+ unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to.
- std::chrono::steady_clock::time_point m_lastPeersRequest;
- unsigned m_idealPeerCount = 5;
+ // Our addresses.
+ std::vector m_addresses; ///< Addresses for us.
+ std::vector m_peerAddresses; ///< Addresses that peers (can) know us by.
- std::vector m_addresses;
- std::vector m_peerAddresses;
+ // Our capabilities.
+ std::map> m_capabilities; ///< Each of the capabilities we support.
- std::map> m_capabilities;
+ 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/HostCapability.cpp b/libp2p/HostCapability.cpp
index 2f295afd0..0728bef2c 100644
--- a/libp2p/HostCapability.cpp
+++ b/libp2p/HostCapability.cpp
@@ -34,7 +34,7 @@ void HostCapabilityFace::seal(bytes& _b)
std::vector > HostCapabilityFace::peers() const
{
- Guard l(m_host->x_peers);
+ RecursiveGuard l(m_host->x_peers);
std::vector > ret;
for (auto const& i: m_host->m_peers)
if (std::shared_ptr p = i.second.lock())
diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp
index d6a45bfc7..5a66064f8 100644
--- a/libp2p/Session.cpp
+++ b/libp2p/Session.cpp
@@ -36,19 +36,38 @@ using namespace dev::p2p;
#endif
#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << m_socket.native_handle() << "] "
-Session::Session(Host* _s, bi::tcp::socket _socket, bi::address _peerAddress, unsigned short _peerPort):
+Session::Session(Host* _s, bi::tcp::socket _socket, bi::tcp::endpoint const& _manual):
m_server(_s),
m_socket(std::move(_socket)),
- m_listenPort(_peerPort),
- m_rating(0)
+ m_node(nullptr),
+ 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_info = PeerInfo({"?", _peerAddress.to_string(), m_listenPort, std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()});
+ m_lastReceived = m_connect = std::chrono::steady_clock::now();
+
+ 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):
+ m_server(_s),
+ m_socket(std::move(_socket)),
+ m_node(_n),
+ m_manualEndpoint(_n->address),
+ m_force(_force)
+{
+ 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 (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)
i.second.reset();
@@ -61,21 +80,103 @@ Session::~Session()
catch (...){}
}
+NodeId Session::id() const
+{
+ return m_node ? m_node->id : NodeId();
+}
+
+void Session::addRating(unsigned _r)
+{
+ if (m_node)
+ {
+ m_node->rating += _r;
+ m_node->score += _r;
+ }
+}
+
+int Session::rating() const
+{
+ return m_node->rating;
+}
+
bi::tcp::endpoint Session::endpoint() const
{
- if (m_socket.is_open())
+ if (m_socket.is_open() && m_node)
try
{
- return bi::tcp::endpoint(m_socket.remote_endpoint().address(), m_listenPort);
+ return bi::tcp::endpoint(m_socket.remote_endpoint().address(), m_node->address.port());
}
- catch (...){}
+ catch (...) {}
+
+ if (m_node)
+ return m_node->address;
- return bi::tcp::endpoint();
+ return m_manualEndpoint;
+}
+
+template vector randomSelection(vector const& _t, unsigned _n)
+{
+ if (_t.size() <= _n)
+ return _t;
+ vector ret = _t;
+ while (ret.size() > _n)
+ {
+ auto i = ret.begin();
+ advance(i, rand() % ret.size());
+ ret.erase(i);
+ }
+ 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.
+ {
+
switch ((PacketType)_r[0].toInt())
{
case HelloPacket:
@@ -83,8 +184,8 @@ bool Session::interpret(RLP const& _r)
m_protocolVersion = _r[1].toInt();
auto clientVersion = _r[2].toString();
auto caps = _r[3].toVector();
- m_listenPort = _r[4].toInt