From a60d88379fb6b479764f5c6d27cda6b29ebc70d9 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 27 Apr 2015 21:42:51 +0200 Subject: [PATCH 01/87] v8 integration initial commit --- CMakeLists.txt | 1 + cmake/EthDependencies.cmake | 4 ++ cmake/Findv8.cmake | 69 ++++++++++++++++++++++ libdevcore/CommonIO.cpp | 2 +- libethconsole/CMakeLists.txt | 28 +++++++++ libethconsole/JSScope.cpp | 5 ++ libethconsole/JSScope.h | 25 ++++++++ libethconsole/JSV8ScopeBase.cpp | 87 ++++++++++++++++++++++++++++ libethconsole/JSV8ScopeBase.h | 69 ++++++++++++++++++++++ test/CMakeLists.txt | 4 ++ test/libethconsole/CMakeLists.txt | 7 +++ test/libethconsole/JSV8ScopeBase.cpp | 21 +++++++ 12 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 cmake/Findv8.cmake create mode 100644 libethconsole/CMakeLists.txt create mode 100644 libethconsole/JSScope.cpp create mode 100644 libethconsole/JSScope.h create mode 100644 libethconsole/JSV8ScopeBase.cpp create mode 100644 libethconsole/JSV8ScopeBase.h create mode 100644 test/libethconsole/CMakeLists.txt create mode 100644 test/libethconsole/JSV8ScopeBase.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ff8732156..7e9ec4742 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -327,6 +327,7 @@ if (JSONRPC) add_subdirectory(libweb3jsonrpc) endif() +add_subdirectory(libethconsole) add_subdirectory(secp256k1) add_subdirectory(libp2p) add_subdirectory(libdevcrypto) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 2dfb80ac3..1edc33b65 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -47,6 +47,10 @@ find_package (LevelDB REQUIRED) message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}") message(" - LevelDB lib: ${LEVELDB_LIBRARIES}") +find_package (v8 REQUIRED) +message(" - v8 header: ${V8_INCLUDE_DIRS}") +message(" - v8 lib : ${V8_LIBRARIES}") + # TODO the Jsoncpp package does not yet check for correct version number find_package (Jsoncpp 0.60 REQUIRED) message(" - Jsoncpp header: ${JSONCPP_INCLUDE_DIRS}") diff --git a/cmake/Findv8.cmake b/cmake/Findv8.cmake new file mode 100644 index 000000000..49c797586 --- /dev/null +++ b/cmake/Findv8.cmake @@ -0,0 +1,69 @@ +# Find v8 +# +# Find the v8 includes and library +# +# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH +# +# This module defines +# V8_INCLUDE_DIRS, where to find header, etc. +# V8_LIBRARIES, the libraries needed to use v8. +# V8_FOUND, If false, do not try to use v8. + +# only look in default directories +find_path( + V8_INCLUDE_DIR + NAMES v8.h + DOC "v8 include dir" +) + +find_library( + V8_LIBRARY + NAMES v8 + DOC "v8 library" +) + +find_library( + V8_BASE_LIBRARY + NAMES v8_base + DOC "v8 library" +) + +find_library( + V8_LIBBASE_LIBRARY + NAMES v8_libbase + DOC "v8 library" +) + +find_library( + V8_LIBPLATFORM_LIBRARY + NAMES v8_libplatform + DOC "v8 library" +) + +string(REPLACE "/include" "" V8_INCLUDE_DIR_LOCATION ${V8_INCLUDE_DIR}) + +set(V8_INCLUDE_DIRS ${V8_INCLUDE_DIR} ${V8_INCLUDE_DIR_LOCATION}) +set(V8_LIBRARIES ${V8_LIBRARY} ${V8_BASE_LIBRARY} ${V8_LIBBASE_LIBRARY} ${V8_LIBPLATFORM_LIBRARY}) + +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + + find_library( + V8_LIBRARY_DEBUG + NAMES v8d + DOC "v8 debug library" + ) + + set(V8_LIBRARIES optimized ${V8_LIBRARIES} debug ${V8_LIBRARY_DEBUG}) + +endif() + +# handle the QUIETLY and REQUIRED arguments and set V8_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(v8 DEFAULT_MSG + V8_INCLUDE_DIR V8_LIBRARY) +mark_as_advanced (V8_INCLUDE_DIR V8_LIBRARY) + diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index a1a1056cb..cf98254c4 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -30,7 +30,7 @@ string dev::memDump(bytes const& _bytes, unsigned _width, bool _html) { stringstream ret; if (_html) - ret << "
";
+		ret << "
";
 	for (unsigned i = 0; i < _bytes.size(); i += _width)
 	{
 		ret << hex << setw(4) << setfill('0') << i << " ";
diff --git a/libethconsole/CMakeLists.txt b/libethconsole/CMakeLists.txt
new file mode 100644
index 000000000..d62da84ff
--- /dev/null
+++ b/libethconsole/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_policy(SET CMP0015 NEW)
+# this policy was introduced in cmake 3.0
+# remove if, once 3.0 will be used on unix
+if (${CMAKE_MAJOR_VERSION} GREATER 2)
+	# old policy do not use MACOSX_RPATH
+	cmake_policy(SET CMP0042 OLD)
+endif()
+
+set(CMAKE_AUTOMOC OFF)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
+
+aux_source_directory(. SRC_LIST)
+
+include_directories(BEFORE ..)
+include_directories(${V8_INCLUDE_DIRS})
+
+set(EXECUTABLE ethconsole)
+
+file(GLOB HEADERS "*.h")
+
+add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
+
+target_link_libraries(${EXECUTABLE} ${V8_LIBRARIES})
+
+install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
+install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )
+
diff --git a/libethconsole/JSScope.cpp b/libethconsole/JSScope.cpp
new file mode 100644
index 000000000..10795e9b0
--- /dev/null
+++ b/libethconsole/JSScope.cpp
@@ -0,0 +1,5 @@
+//
+// Created by Marek Kotewicz on 27/04/15.
+//
+
+#include "JSScope.h"
diff --git a/libethconsole/JSScope.h b/libethconsole/JSScope.h
new file mode 100644
index 000000000..18d6c863c
--- /dev/null
+++ b/libethconsole/JSScope.h
@@ -0,0 +1,25 @@
+//
+// Created by Marek Kotewicz on 27/04/15.
+//
+
+#pragma once
+
+namespace dev
+{
+namespace eth
+{
+
+class JSScope
+{
+public:
+	JSScope()
+	{ };
+
+	virtual ~JSScope()
+	{ };
+
+	virtual const char* evaluate(const char* _cstr) const = 0;
+};
+
+}
+}
diff --git a/libethconsole/JSV8ScopeBase.cpp b/libethconsole/JSV8ScopeBase.cpp
new file mode 100644
index 000000000..9e3516812
--- /dev/null
+++ b/libethconsole/JSV8ScopeBase.cpp
@@ -0,0 +1,87 @@
+//
+// Created by Marek Kotewicz on 27/04/15.
+//
+
+#include 
+#include 
+#include "JSV8ScopeBase.h"
+
+using namespace dev;
+using namespace dev::eth;
+
+JSV8Env JSV8ScopeBase::s_env = JSV8Env();
+
+class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+public:
+	virtual void* Allocate(size_t length) {
+		void* data = AllocateUninitialized(length);
+		return data == NULL ? data : memset(data, 0, length);
+	}
+	virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
+	virtual void Free(void* data, size_t) { free(data); }
+};
+
+JSV8Env::JSV8Env()
+{
+	static bool initialized = false;
+	if (initialized)
+		return;
+	initialized = true;
+	v8::V8::InitializeICU();
+	m_platform = v8::platform::CreateDefaultPlatform();
+	v8::V8::InitializePlatform(m_platform);
+	v8::V8::Initialize();
+	ShellArrayBufferAllocator array_buffer_allocator;
+	v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
+}
+
+JSV8Env::~JSV8Env()
+{
+	v8::V8::Dispose();
+	v8::V8::ShutdownPlatform();
+	delete m_platform;
+}
+
+JSV8ScopeBase::JSV8ScopeBase():
+		m_isolate(v8::Isolate::New()),
+		m_scope(new JSV8DumbScope(m_isolate))
+{ }
+
+JSV8ScopeBase::~JSV8ScopeBase()
+{
+	delete m_scope;
+	m_isolate->Dispose();
+}
+
+const char* JSV8ScopeBase::evaluate(const char* _cstr) const
+{
+	v8::HandleScope handleScope(m_isolate);
+//	v8::TryCatch tryCatch;
+	v8::Local source = v8::String::NewFromUtf8(m_scope->context()->GetIsolate(), _cstr);
+	v8::Local name(v8::String::NewFromUtf8(m_scope->context()->GetIsolate(), "(shell)"));
+	v8::ScriptOrigin origin(name);
+	v8::Handle script = v8::Script::Compile(source, &origin);
+	if (script.IsEmpty())
+	{
+		// TODO: handle exceptions
+		return "";
+	}
+
+	v8::Handle result = script->Run();
+	return formatValue(result);
+}
+
+const char* JSV8ScopeBase::formatValue(v8::Handle const &_value) const
+{
+	if (_value.IsEmpty())
+	{
+		// TODO: handle exceptions
+		return "";
+	}
+	else if (_value->IsUndefined())
+	{
+		return "undefined";
+	}
+	v8::String::Utf8Value str(_value);
+	return *str ? *str : "";
+}
diff --git a/libethconsole/JSV8ScopeBase.h b/libethconsole/JSV8ScopeBase.h
new file mode 100644
index 000000000..2f7d46c79
--- /dev/null
+++ b/libethconsole/JSV8ScopeBase.h
@@ -0,0 +1,69 @@
+//
+// Created by Marek Kotewicz on 27/04/15.
+//
+
+#pragma once
+
+#include 
+#include "JSScope.h"
+
+namespace dev
+{
+namespace eth
+{
+
+class JSV8Env
+{
+public:
+	JSV8Env();
+	~JSV8Env();
+
+private:
+	v8::Platform* m_platform;
+};
+
+v8::Handle CreateShellContext(v8::Isolate* isolate)
+{
+	v8::Handle global = v8::ObjectTemplate::New(isolate);
+	return v8::Context::New(isolate, NULL, global);
+}
+
+class JSV8DumbScope
+{
+public:
+	JSV8DumbScope(v8::Isolate* _isolate):
+			m_isolateScope(_isolate),
+			m_handleScope(_isolate),
+			m_context(CreateShellContext(_isolate)),
+			m_contextScope(m_context)
+	{}
+
+	v8::Handle  const& context() const { return m_context; }
+
+private:
+	v8::Isolate::Scope m_isolateScope;
+	v8::HandleScope m_handleScope;
+	v8::Handle  m_context;
+	v8::Context::Scope m_contextScope;
+};
+
+class JSV8ScopeBase : public JSScope
+{
+public:
+	JSV8ScopeBase();
+
+	virtual ~JSV8ScopeBase();
+
+	const char* evaluate(const char* _cstr) const;
+
+private:
+	static JSV8Env s_env;
+	v8::Isolate* m_isolate;
+	JSV8DumbScope* m_scope;
+
+	virtual const char* formatValue(v8::Handle  const &_value) const;
+};
+
+}
+}
+
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index a97bb86fc..2413fc0a9 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -25,6 +25,8 @@ add_subdirectory(libethereum)
 add_subdirectory(libevm)
 add_subdirectory(libnatspec)
 add_subdirectory(libp2p)
+add_subdirectory(libethconsole)
+
 if (SOLIDITY)
 	add_subdirectory(libsolidity)
 endif ()
@@ -40,6 +42,7 @@ include_directories(BEFORE ..)
 include_directories(${Boost_INCLUDE_DIRS})
 include_directories(${CRYPTOPP_INCLUDE_DIRS})
 include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
+include_directories(${V8_INCLUDE_DIRS})
 
 # search for test names and create ctest tests
 enable_testing()
@@ -65,6 +68,7 @@ target_link_libraries(testeth ${CURL_LIBRARIES})
 target_link_libraries(testeth ethereum)
 target_link_libraries(testeth ethcore)
 target_link_libraries(testeth secp256k1)
+target_link_libraries(testeth ethconsole)
 if (SOLIDITY)
 	target_link_libraries(testeth solidity)
 endif ()
diff --git a/test/libethconsole/CMakeLists.txt b/test/libethconsole/CMakeLists.txt
new file mode 100644
index 000000000..610c58889
--- /dev/null
+++ b/test/libethconsole/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0015 NEW)
+
+aux_source_directory(. SRCS)
+
+add_sources(${SRCS})
+
+
diff --git a/test/libethconsole/JSV8ScopeBase.cpp b/test/libethconsole/JSV8ScopeBase.cpp
new file mode 100644
index 000000000..5bd7bf6a5
--- /dev/null
+++ b/test/libethconsole/JSV8ScopeBase.cpp
@@ -0,0 +1,21 @@
+//
+// Created by Marek Kotewicz on 27/04/15.
+//
+
+#include 
+#include "../../libethconsole/JSV8ScopeBase.h"
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+
+BOOST_AUTO_TEST_SUITE(jsscope)
+
+BOOST_AUTO_TEST_CASE(common)
+{
+	JSV8ScopeBase scope;
+	string result = scope.evaluate("1 + 1");
+	BOOST_CHECK_EQUAL(result, "2");
+}
+
+BOOST_AUTO_TEST_SUITE_END()

From 72afc0c7d1602d6b24a574ec117631816553a798 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Mon, 27 Apr 2015 22:20:57 +0200
Subject: [PATCH 02/87] cleanup, libjsengine

---
 CMakeLists.txt                                |  2 +-
 libdevcore/CommonIO.cpp                       |  2 +-
 libethconsole/JSV8ScopeBase.h                 | 69 -----------------
 {libethconsole => libjsengine}/CMakeLists.txt |  6 +-
 .../JSScope.cpp => libjsengine/JSEngine.cpp   |  2 +-
 .../JSScope.h => libjsengine/JSEngine.h       | 11 +--
 .../JSV8Engine.cpp                            | 76 ++++++++++++++++---
 libjsengine/JSV8Engine.h                      | 37 +++++++++
 test/CMakeLists.txt                           |  4 +-
 .../CMakeLists.txt                            |  0
 .../JSV8ScopeBase.cpp                         |  4 +-
 11 files changed, 116 insertions(+), 97 deletions(-)
 delete mode 100644 libethconsole/JSV8ScopeBase.h
 rename {libethconsole => libjsengine}/CMakeLists.txt (79%)
 rename libethconsole/JSScope.cpp => libjsengine/JSEngine.cpp (69%)
 rename libethconsole/JSScope.h => libjsengine/JSEngine.h (61%)
 rename libethconsole/JSV8ScopeBase.cpp => libjsengine/JSV8Engine.cpp (52%)
 create mode 100644 libjsengine/JSV8Engine.h
 rename test/{libethconsole => libjsengine}/CMakeLists.txt (100%)
 rename test/{libethconsole => libjsengine}/JSV8ScopeBase.cpp (82%)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7e9ec4742..75aa0d80b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -327,7 +327,7 @@ if (JSONRPC)
 	add_subdirectory(libweb3jsonrpc)
 endif()
 
-add_subdirectory(libethconsole)
+add_subdirectory(libjsengine)
 add_subdirectory(secp256k1)
 add_subdirectory(libp2p)
 add_subdirectory(libdevcrypto)
diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp
index cf98254c4..5b90a9079 100644
--- a/libdevcore/CommonIO.cpp
+++ b/libdevcore/CommonIO.cpp
@@ -30,7 +30,7 @@ string dev::memDump(bytes const& _bytes, unsigned _width, bool _html)
 {
 	stringstream ret;
 	if (_html)
-		ret << "
";
+		ret << "
";
 	for (unsigned i = 0; i < _bytes.size(); i += _width)
 	{
 		ret << hex << setw(4) << setfill('0') << i << " ";
diff --git a/libethconsole/JSV8ScopeBase.h b/libethconsole/JSV8ScopeBase.h
deleted file mode 100644
index 2f7d46c79..000000000
--- a/libethconsole/JSV8ScopeBase.h
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// Created by Marek Kotewicz on 27/04/15.
-//
-
-#pragma once
-
-#include 
-#include "JSScope.h"
-
-namespace dev
-{
-namespace eth
-{
-
-class JSV8Env
-{
-public:
-	JSV8Env();
-	~JSV8Env();
-
-private:
-	v8::Platform* m_platform;
-};
-
-v8::Handle CreateShellContext(v8::Isolate* isolate)
-{
-	v8::Handle global = v8::ObjectTemplate::New(isolate);
-	return v8::Context::New(isolate, NULL, global);
-}
-
-class JSV8DumbScope
-{
-public:
-	JSV8DumbScope(v8::Isolate* _isolate):
-			m_isolateScope(_isolate),
-			m_handleScope(_isolate),
-			m_context(CreateShellContext(_isolate)),
-			m_contextScope(m_context)
-	{}
-
-	v8::Handle  const& context() const { return m_context; }
-
-private:
-	v8::Isolate::Scope m_isolateScope;
-	v8::HandleScope m_handleScope;
-	v8::Handle  m_context;
-	v8::Context::Scope m_contextScope;
-};
-
-class JSV8ScopeBase : public JSScope
-{
-public:
-	JSV8ScopeBase();
-
-	virtual ~JSV8ScopeBase();
-
-	const char* evaluate(const char* _cstr) const;
-
-private:
-	static JSV8Env s_env;
-	v8::Isolate* m_isolate;
-	JSV8DumbScope* m_scope;
-
-	virtual const char* formatValue(v8::Handle  const &_value) const;
-};
-
-}
-}
-
diff --git a/libethconsole/CMakeLists.txt b/libjsengine/CMakeLists.txt
similarity index 79%
rename from libethconsole/CMakeLists.txt
rename to libjsengine/CMakeLists.txt
index d62da84ff..aaf933eb6 100644
--- a/libethconsole/CMakeLists.txt
+++ b/libjsengine/CMakeLists.txt
@@ -8,6 +8,8 @@ endif()
 
 set(CMAKE_AUTOMOC OFF)
 
+# macos brew version of v8 needs to be compiled with libstdc++
+# it also needs to be dynamic library
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
 
 aux_source_directory(. SRC_LIST)
@@ -15,11 +17,11 @@ aux_source_directory(. SRC_LIST)
 include_directories(BEFORE ..)
 include_directories(${V8_INCLUDE_DIRS})
 
-set(EXECUTABLE ethconsole)
+set(EXECUTABLE jsengine)
 
 file(GLOB HEADERS "*.h")
 
-add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
+add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 
 target_link_libraries(${EXECUTABLE} ${V8_LIBRARIES})
 
diff --git a/libethconsole/JSScope.cpp b/libjsengine/JSEngine.cpp
similarity index 69%
rename from libethconsole/JSScope.cpp
rename to libjsengine/JSEngine.cpp
index 10795e9b0..45898cacd 100644
--- a/libethconsole/JSScope.cpp
+++ b/libjsengine/JSEngine.cpp
@@ -2,4 +2,4 @@
 // Created by Marek Kotewicz on 27/04/15.
 //
 
-#include "JSScope.h"
+#include "JSEngine.h"
diff --git a/libethconsole/JSScope.h b/libjsengine/JSEngine.h
similarity index 61%
rename from libethconsole/JSScope.h
rename to libjsengine/JSEngine.h
index 18d6c863c..5f39fe937 100644
--- a/libethconsole/JSScope.h
+++ b/libjsengine/JSEngine.h
@@ -9,15 +9,12 @@ namespace dev
 namespace eth
 {
 
-class JSScope
+class JSEngine
 {
 public:
-	JSScope()
-	{ };
-
-	virtual ~JSScope()
-	{ };
-
+	JSEngine() {};
+	virtual ~JSEngine() {};
+	// should be used to evalute javascript expression
 	virtual const char* evaluate(const char* _cstr) const = 0;
 };
 
diff --git a/libethconsole/JSV8ScopeBase.cpp b/libjsengine/JSV8Engine.cpp
similarity index 52%
rename from libethconsole/JSV8ScopeBase.cpp
rename to libjsengine/JSV8Engine.cpp
index 9e3516812..ac0370042 100644
--- a/libethconsole/JSV8ScopeBase.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -4,12 +4,15 @@
 
 #include 
 #include 
-#include "JSV8ScopeBase.h"
+#include "JSV8Engine.h"
 
 using namespace dev;
 using namespace dev::eth;
 
-JSV8Env JSV8ScopeBase::s_env = JSV8Env();
+namespace dev
+{
+namespace eth
+{
 
 class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
 public:
@@ -21,6 +24,52 @@ public:
 	virtual void Free(void* data, size_t) { free(data); }
 };
 
+class JSV8Env
+{
+public:
+	JSV8Env();
+
+	~JSV8Env();
+
+private:
+	v8::Platform *m_platform;
+};
+
+v8::Handle createShellContext(v8::Isolate* isolate)
+{
+	v8::Handle global = v8::ObjectTemplate::New(isolate);
+	v8::Handle context = v8::Context::New(isolate, NULL, global);
+	if (context.IsEmpty())
+	{
+		// TODO: throw an exception
+	}
+	return context;
+}
+
+class JSV8Scope
+{
+public:
+	JSV8Scope(v8::Isolate* _isolate):
+			m_isolateScope(_isolate),
+			m_handleScope(_isolate),
+			m_context(createShellContext(_isolate)),
+			m_contextScope(m_context)
+	{}
+
+	v8::Handle  const& context() const { return m_context; }
+
+private:
+	v8::Isolate::Scope m_isolateScope;
+	v8::HandleScope m_handleScope;
+	v8::Handle  m_context;
+	v8::Context::Scope m_contextScope;
+};
+
+}
+}
+
+JSV8Env JSV8Engine::s_env = JSV8Env();
+
 JSV8Env::JSV8Env()
 {
 	static bool initialized = false;
@@ -42,23 +91,23 @@ JSV8Env::~JSV8Env()
 	delete m_platform;
 }
 
-JSV8ScopeBase::JSV8ScopeBase():
+JSV8Engine::JSV8Engine():
 		m_isolate(v8::Isolate::New()),
-		m_scope(new JSV8DumbScope(m_isolate))
+		m_scope(new JSV8Scope(m_isolate))
 { }
 
-JSV8ScopeBase::~JSV8ScopeBase()
+JSV8Engine::~JSV8Engine()
 {
 	delete m_scope;
 	m_isolate->Dispose();
 }
 
-const char* JSV8ScopeBase::evaluate(const char* _cstr) const
+const char* JSV8Engine::evaluate(const char* _cstr) const
 {
 	v8::HandleScope handleScope(m_isolate);
 //	v8::TryCatch tryCatch;
-	v8::Local source = v8::String::NewFromUtf8(m_scope->context()->GetIsolate(), _cstr);
-	v8::Local name(v8::String::NewFromUtf8(m_scope->context()->GetIsolate(), "(shell)"));
+	v8::Local source = v8::String::NewFromUtf8(context()->GetIsolate(), _cstr);
+	v8::Local name(v8::String::NewFromUtf8(context()->GetIsolate(), "(shell)"));
 	v8::ScriptOrigin origin(name);
 	v8::Handle script = v8::Script::Compile(source, &origin);
 	if (script.IsEmpty())
@@ -68,10 +117,15 @@ const char* JSV8ScopeBase::evaluate(const char* _cstr) const
 	}
 
 	v8::Handle result = script->Run();
-	return formatValue(result);
+	return formatOutputValue(result);
 }
 
-const char* JSV8ScopeBase::formatValue(v8::Handle const &_value) const
+v8::Handle const& JSV8Engine::context() const
+{
+	return m_scope->context();
+}
+
+const char* JSV8Engine::formatOutputValue(v8::Handle const& _value) const
 {
 	if (_value.IsEmpty())
 	{
@@ -79,9 +133,7 @@ const char* JSV8ScopeBase::formatValue(v8::Handle const &_value) cons
 		return "";
 	}
 	else if (_value->IsUndefined())
-	{
 		return "undefined";
-	}
 	v8::String::Utf8Value str(_value);
 	return *str ? *str : "";
 }
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
new file mode 100644
index 000000000..ebcf80402
--- /dev/null
+++ b/libjsengine/JSV8Engine.h
@@ -0,0 +1,37 @@
+//
+// Created by Marek Kotewicz on 27/04/15.
+//
+
+#pragma once
+
+#include 
+#include "JSEngine.h"
+
+namespace dev
+{
+namespace eth
+{
+
+class JSV8Env;
+class JSV8Scope;
+
+class JSV8Engine : public JSEngine
+{
+public:
+	JSV8Engine();
+	virtual ~JSV8Engine();
+	const char* evaluate(const char* _cstr) const;
+
+private:
+	static JSV8Env s_env;
+	v8::Isolate* m_isolate;
+	JSV8Scope* m_scope;
+
+protected:
+	v8::Handle const& context() const;
+	virtual const char* formatOutputValue(v8::Handle const& _value) const;
+};
+
+}
+}
+
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 2413fc0a9..349ca9800 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -25,7 +25,7 @@ add_subdirectory(libethereum)
 add_subdirectory(libevm)
 add_subdirectory(libnatspec)
 add_subdirectory(libp2p)
-add_subdirectory(libethconsole)
+add_subdirectory(libjsengine)
 
 if (SOLIDITY)
 	add_subdirectory(libsolidity)
@@ -68,7 +68,7 @@ target_link_libraries(testeth ${CURL_LIBRARIES})
 target_link_libraries(testeth ethereum)
 target_link_libraries(testeth ethcore)
 target_link_libraries(testeth secp256k1)
-target_link_libraries(testeth ethconsole)
+target_link_libraries(testeth jsengine)
 if (SOLIDITY)
 	target_link_libraries(testeth solidity)
 endif ()
diff --git a/test/libethconsole/CMakeLists.txt b/test/libjsengine/CMakeLists.txt
similarity index 100%
rename from test/libethconsole/CMakeLists.txt
rename to test/libjsengine/CMakeLists.txt
diff --git a/test/libethconsole/JSV8ScopeBase.cpp b/test/libjsengine/JSV8ScopeBase.cpp
similarity index 82%
rename from test/libethconsole/JSV8ScopeBase.cpp
rename to test/libjsengine/JSV8ScopeBase.cpp
index 5bd7bf6a5..cf848e2c9 100644
--- a/test/libethconsole/JSV8ScopeBase.cpp
+++ b/test/libjsengine/JSV8ScopeBase.cpp
@@ -3,7 +3,7 @@
 //
 
 #include 
-#include "../../libethconsole/JSV8ScopeBase.h"
+#include 
 
 using namespace std;
 using namespace dev;
@@ -13,7 +13,7 @@ BOOST_AUTO_TEST_SUITE(jsscope)
 
 BOOST_AUTO_TEST_CASE(common)
 {
-	JSV8ScopeBase scope;
+	JSV8Engine scope;
 	string result = scope.evaluate("1 + 1");
 	BOOST_CHECK_EQUAL(result, "2");
 }

From 41afe1672ecd2baa9f49621d9b2f02a2eeb76d8e Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Tue, 28 Apr 2015 00:43:37 +0200
Subject: [PATCH 03/87] libjsconsole init

---
 CMakeLists.txt                     |  1 +
 libjsconsole/CMakeLists.txt        | 25 +++++++++++++++++++++
 libjsconsole/JSConsole.cpp         |  5 +++++
 libjsconsole/JSConsole.h           | 19 ++++++++++++++++
 libjsconsole/JSV8Console.cpp       | 20 +++++++++++++++++
 libjsconsole/JSV8Console.h         | 29 +++++++++++++++++++++++++
 libjsengine/JSV8Engine.cpp         | 29 +++++++++++++------------
 libjsengine/JSV8Engine.h           |  2 +-
 libjsengine/JSV8Printer.cpp        | 18 +++++++++++++++
 libjsengine/JSV8Printer.h          | 23 ++++++++++++++++++++
 test/libjsengine/CMakeLists.txt    |  2 --
 test/libjsengine/JSV8Engine.cpp    | 35 ++++++++++++++++++++++++++++++
 test/libjsengine/JSV8ScopeBase.cpp | 21 ------------------
 13 files changed, 191 insertions(+), 38 deletions(-)
 create mode 100644 libjsconsole/CMakeLists.txt
 create mode 100644 libjsconsole/JSConsole.cpp
 create mode 100644 libjsconsole/JSConsole.h
 create mode 100644 libjsconsole/JSV8Console.cpp
 create mode 100644 libjsconsole/JSV8Console.h
 create mode 100644 libjsengine/JSV8Printer.cpp
 create mode 100644 libjsengine/JSV8Printer.h
 create mode 100644 test/libjsengine/JSV8Engine.cpp
 delete mode 100644 test/libjsengine/JSV8ScopeBase.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 75aa0d80b..97d108e6c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -328,6 +328,7 @@ if (JSONRPC)
 endif()
 
 add_subdirectory(libjsengine)
+add_subdirectory(libjsconsole)
 add_subdirectory(secp256k1)
 add_subdirectory(libp2p)
 add_subdirectory(libdevcrypto)
diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt
new file mode 100644
index 000000000..cac47fc6c
--- /dev/null
+++ b/libjsconsole/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_policy(SET CMP0015 NEW)
+# this policy was introduced in cmake 3.0
+# remove if, once 3.0 will be used on unix
+if (${CMAKE_MAJOR_VERSION} GREATER 2)
+	# old policy do not use MACOSX_RPATH
+	cmake_policy(SET CMP0042 OLD)
+endif()
+
+set(CMAKE_AUTOMOC OFF)
+
+aux_source_directory(. SRC_LIST)
+
+include_directories(BEFORE ..)
+include_directories(${V8_INCLUDE_DIRS})
+
+set(EXECUTABLE jsconsole)
+
+file(GLOB HEADERS "*.h")
+
+add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
+
+target_link_libraries(${EXECUTABLE} jsengine)
+
+install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
+install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
new file mode 100644
index 000000000..5ba1912ff
--- /dev/null
+++ b/libjsconsole/JSConsole.cpp
@@ -0,0 +1,5 @@
+//
+// Created by Marek Kotewicz on 28/04/15.
+//
+
+#include "JSConsole.h"
diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h
new file mode 100644
index 000000000..3e9124114
--- /dev/null
+++ b/libjsconsole/JSConsole.h
@@ -0,0 +1,19 @@
+//
+// Created by Marek Kotewicz on 28/04/15.
+//
+
+#pragma once
+
+namespace dev
+{
+namespace eth
+{
+
+class JSConsole
+{
+public:
+	virtual void repl() const = 0;
+};
+
+}
+}
diff --git a/libjsconsole/JSV8Console.cpp b/libjsconsole/JSV8Console.cpp
new file mode 100644
index 000000000..7889b24c5
--- /dev/null
+++ b/libjsconsole/JSV8Console.cpp
@@ -0,0 +1,20 @@
+//
+// Created by Marek Kotewicz on 28/04/15.
+//
+
+#include 
+#include 
+#include "JSV8Console.h"
+
+using namespace dev;
+using namespace dev::eth;
+
+JSV8Console::JSV8Console(): m_engine(), m_printer(m_engine)
+{
+
+}
+
+void JSV8Console::repl() const
+{
+
+}
diff --git a/libjsconsole/JSV8Console.h b/libjsconsole/JSV8Console.h
new file mode 100644
index 000000000..929a56f0b
--- /dev/null
+++ b/libjsconsole/JSV8Console.h
@@ -0,0 +1,29 @@
+//
+// Created by Marek Kotewicz on 28/04/15.
+//
+
+#pragma once
+
+#include "JSConsole.h"
+
+namespace dev
+{
+namespace eth
+{
+
+class JSV8Engine;
+class JSV8Printer;
+
+class JSV8Console : public JSConsole
+{
+public:
+	JSV8Console();
+	void repl() const;
+
+private:
+	JSV8Engine m_engine;
+	JSV8Printer m_printer;
+};
+
+}
+}
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index ac0370042..80c28a3dd 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -2,8 +2,8 @@
 // Created by Marek Kotewicz on 27/04/15.
 //
 
-#include 
 #include 
+#include 
 #include "JSV8Engine.h"
 
 using namespace dev;
@@ -94,7 +94,7 @@ JSV8Env::~JSV8Env()
 JSV8Engine::JSV8Engine():
 		m_isolate(v8::Isolate::New()),
 		m_scope(new JSV8Scope(m_isolate))
-{ }
+{}
 
 JSV8Engine::~JSV8Engine()
 {
@@ -102,7 +102,7 @@ JSV8Engine::~JSV8Engine()
 	m_isolate->Dispose();
 }
 
-const char* JSV8Engine::evaluate(const char* _cstr) const
+v8::Handle JSV8Engine::eval(const char* _cstr) const
 {
 	v8::HandleScope handleScope(m_isolate);
 //	v8::TryCatch tryCatch;
@@ -113,27 +113,28 @@ const char* JSV8Engine::evaluate(const char* _cstr) const
 	if (script.IsEmpty())
 	{
 		// TODO: handle exceptions
-		return "";
+		return v8::Handle();
 	}
 
-	v8::Handle result = script->Run();
-	return formatOutputValue(result);
+	return script->Run();
 }
 
-v8::Handle const& JSV8Engine::context() const
+const char* JSV8Engine::evaluate(const char* _cstr) const
 {
-	return m_scope->context();
-}
+	v8::Handle value = (eval(_cstr));
 
-const char* JSV8Engine::formatOutputValue(v8::Handle const& _value) const
-{
-	if (_value.IsEmpty())
+	if (value.IsEmpty())
 	{
 		// TODO: handle exceptions
 		return "";
 	}
-	else if (_value->IsUndefined())
+	else if (value->IsUndefined())
 		return "undefined";
-	v8::String::Utf8Value str(_value);
+	v8::String::Utf8Value str(value);
 	return *str ? *str : "";
 }
+
+v8::Handle const& JSV8Engine::context() const
+{
+	return m_scope->context();
+}
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
index ebcf80402..a8d8d4a6c 100644
--- a/libjsengine/JSV8Engine.h
+++ b/libjsengine/JSV8Engine.h
@@ -20,6 +20,7 @@ class JSV8Engine : public JSEngine
 public:
 	JSV8Engine();
 	virtual ~JSV8Engine();
+	v8::Handle eval(const char* _cstr) const;
 	const char* evaluate(const char* _cstr) const;
 
 private:
@@ -29,7 +30,6 @@ private:
 
 protected:
 	v8::Handle const& context() const;
-	virtual const char* formatOutputValue(v8::Handle const& _value) const;
 };
 
 }
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
new file mode 100644
index 000000000..d61489d56
--- /dev/null
+++ b/libjsengine/JSV8Printer.cpp
@@ -0,0 +1,18 @@
+//
+// Created by Marek Kotewicz on 28/04/15.
+//
+
+#include "JSV8Printer.h"
+
+using namespace dev;
+using namespace eth;
+
+JSV8Printer::JSV8Printer(JSV8Engine const& _engine)
+{
+
+}
+
+const char* JSV8Printer::print(v8::Handle const& _value) const
+{
+	return "";
+}
diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h
new file mode 100644
index 000000000..08113960a
--- /dev/null
+++ b/libjsengine/JSV8Printer.h
@@ -0,0 +1,23 @@
+//
+// Created by Marek Kotewicz on 28/04/15.
+//
+
+#pragma once
+
+#include "JSV8Engine.h"
+
+
+namespace dev
+{
+namespace eth
+{
+
+class JSV8Printer
+{
+public:
+	JSV8Printer(JSV8Engine const& _engine);
+	const char* print(v8::Handle const& _value) const;
+};
+
+}
+}
diff --git a/test/libjsengine/CMakeLists.txt b/test/libjsengine/CMakeLists.txt
index 610c58889..3ceda13b0 100644
--- a/test/libjsengine/CMakeLists.txt
+++ b/test/libjsengine/CMakeLists.txt
@@ -3,5 +3,3 @@ cmake_policy(SET CMP0015 NEW)
 aux_source_directory(. SRCS)
 
 add_sources(${SRCS})
-
-
diff --git a/test/libjsengine/JSV8Engine.cpp b/test/libjsengine/JSV8Engine.cpp
new file mode 100644
index 000000000..b65f07d4d
--- /dev/null
+++ b/test/libjsengine/JSV8Engine.cpp
@@ -0,0 +1,35 @@
+//
+// Created by Marek Kotewicz on 27/04/15.
+//
+
+#include 
+#include 
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+
+BOOST_AUTO_TEST_SUITE(jsv8engine)
+
+BOOST_AUTO_TEST_CASE(evalInteger)
+{
+	JSV8Engine scope;
+	string result = scope.evaluate("1 + 1");
+	BOOST_CHECK_EQUAL(result, "2");
+}
+
+BOOST_AUTO_TEST_CASE(evalString)
+{
+	JSV8Engine scope;
+	string result = scope.evaluate("'hello ' + 'world'");
+	BOOST_CHECK_EQUAL(result, "hello world");
+}
+
+BOOST_AUTO_TEST_CASE(evalEmpty)
+{
+	JSV8Engine scope;
+	string result = scope.evaluate("");
+	BOOST_CHECK_EQUAL(result, "undefined");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libjsengine/JSV8ScopeBase.cpp b/test/libjsengine/JSV8ScopeBase.cpp
deleted file mode 100644
index cf848e2c9..000000000
--- a/test/libjsengine/JSV8ScopeBase.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Created by Marek Kotewicz on 27/04/15.
-//
-
-#include 
-#include 
-
-using namespace std;
-using namespace dev;
-using namespace dev::eth;
-
-BOOST_AUTO_TEST_SUITE(jsscope)
-
-BOOST_AUTO_TEST_CASE(common)
-{
-	JSV8Engine scope;
-	string result = scope.evaluate("1 + 1");
-	BOOST_CHECK_EQUAL(result, "2");
-}
-
-BOOST_AUTO_TEST_SUITE_END()

From 2107e9a02c1c7e5f71e2676646e32613230c672a Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Tue, 28 Apr 2015 08:24:39 +0200
Subject: [PATCH 04/87] jsvalueprinter

---
 libjsengine/CMakeLists.txt      |  1 -
 libjsengine/JSEngine.h          | 11 ++++++++---
 libjsengine/JSPrinter.cpp       |  5 +++++
 libjsengine/JSPrinter.h         | 22 +++++++++++++++++++++
 libjsengine/JSV8Engine.cpp      | 34 ++++++++++++++++-----------------
 libjsengine/JSV8Engine.h        | 17 +++++++++++++----
 libjsengine/JSV8Printer.cpp     |  4 ++--
 libjsengine/JSV8Printer.h       |  5 +++--
 test/libjsengine/JSV8Engine.cpp | 19 ++++++++++++------
 9 files changed, 82 insertions(+), 36 deletions(-)
 create mode 100644 libjsengine/JSPrinter.cpp
 create mode 100644 libjsengine/JSPrinter.h

diff --git a/libjsengine/CMakeLists.txt b/libjsengine/CMakeLists.txt
index aaf933eb6..039e3d162 100644
--- a/libjsengine/CMakeLists.txt
+++ b/libjsengine/CMakeLists.txt
@@ -27,4 +27,3 @@ target_link_libraries(${EXECUTABLE} ${V8_LIBRARIES})
 
 install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
 install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )
-
diff --git a/libjsengine/JSEngine.h b/libjsengine/JSEngine.h
index 5f39fe937..69d13d386 100644
--- a/libjsengine/JSEngine.h
+++ b/libjsengine/JSEngine.h
@@ -9,13 +9,18 @@ namespace dev
 namespace eth
 {
 
+class JSValue
+{
+public:
+	virtual const char* asCString() const = 0;
+};
+
+template 
 class JSEngine
 {
 public:
-	JSEngine() {};
-	virtual ~JSEngine() {};
 	// should be used to evalute javascript expression
-	virtual const char* evaluate(const char* _cstr) const = 0;
+	virtual T eval(const char* _cstr) const = 0;
 };
 
 }
diff --git a/libjsengine/JSPrinter.cpp b/libjsengine/JSPrinter.cpp
new file mode 100644
index 000000000..fbd075fe2
--- /dev/null
+++ b/libjsengine/JSPrinter.cpp
@@ -0,0 +1,5 @@
+//
+// Created by Marek Kotewicz on 28/04/15.
+//
+
+#include "JSPrinter.h"
diff --git a/libjsengine/JSPrinter.h b/libjsengine/JSPrinter.h
new file mode 100644
index 000000000..bd0dd89b5
--- /dev/null
+++ b/libjsengine/JSPrinter.h
@@ -0,0 +1,22 @@
+//
+// Created by Marek Kotewicz on 28/04/15.
+//
+
+#pragma once
+
+#include "JSEngine.h"
+
+namespace dev
+{
+namespace eth
+{
+
+class JSPrinter
+{
+public:
+	virtual const char* print(JSValue const& _value) const { return _value.asCString(); }
+};
+
+}
+}
+
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 80c28a3dd..2538fa409 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -70,6 +70,19 @@ private:
 
 JSV8Env JSV8Engine::s_env = JSV8Env();
 
+const char* JSV8Value::asCString() const
+{
+	if (m_value.IsEmpty())
+	{
+		// TODO: handle exceptions
+		return "";
+	}
+	else if (m_value->IsUndefined())
+		return "undefined";
+	v8::String::Utf8Value str(m_value);
+	return *str ? *str : "";
+}
+
 JSV8Env::JSV8Env()
 {
 	static bool initialized = false;
@@ -102,7 +115,7 @@ JSV8Engine::~JSV8Engine()
 	m_isolate->Dispose();
 }
 
-v8::Handle JSV8Engine::eval(const char* _cstr) const
+JSV8Value JSV8Engine::eval(const char* _cstr) const
 {
 	v8::HandleScope handleScope(m_isolate);
 //	v8::TryCatch tryCatch;
@@ -113,25 +126,10 @@ v8::Handle JSV8Engine::eval(const char* _cstr) const
 	if (script.IsEmpty())
 	{
 		// TODO: handle exceptions
-		return v8::Handle();
+		return JSV8Value(v8::Handle());
 	}
 
-	return script->Run();
-}
-
-const char* JSV8Engine::evaluate(const char* _cstr) const
-{
-	v8::Handle value = (eval(_cstr));
-
-	if (value.IsEmpty())
-	{
-		// TODO: handle exceptions
-		return "";
-	}
-	else if (value->IsUndefined())
-		return "undefined";
-	v8::String::Utf8Value str(value);
-	return *str ? *str : "";
+	return JSV8Value(script->Run());
 }
 
 v8::Handle const& JSV8Engine::context() const
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
index a8d8d4a6c..d020ebb95 100644
--- a/libjsengine/JSV8Engine.h
+++ b/libjsengine/JSV8Engine.h
@@ -15,13 +15,23 @@ namespace eth
 class JSV8Env;
 class JSV8Scope;
 
-class JSV8Engine : public JSEngine
+class JSV8Value : public JSValue
+{
+public:
+	JSV8Value(v8::Handle _value): m_value(_value) {}
+	const char* asCString() const;
+
+	v8::Handle const& value() const { return m_value; }
+private:
+	v8::Handle m_value;
+};
+
+class JSV8Engine : public JSEngine
 {
 public:
 	JSV8Engine();
 	virtual ~JSV8Engine();
-	v8::Handle eval(const char* _cstr) const;
-	const char* evaluate(const char* _cstr) const;
+	JSV8Value eval(const char* _cstr) const;
 
 private:
 	static JSV8Env s_env;
@@ -34,4 +44,3 @@ protected:
 
 }
 }
-
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index d61489d56..80c06d590 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -12,7 +12,7 @@ JSV8Printer::JSV8Printer(JSV8Engine const& _engine)
 
 }
 
-const char* JSV8Printer::print(v8::Handle const& _value) const
+const char* JSV8Printer::prettyPrint(JSV8Value const& _value) const
 {
-	return "";
+	return nullptr;
 }
diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h
index 08113960a..e7bbfab9e 100644
--- a/libjsengine/JSV8Printer.h
+++ b/libjsengine/JSV8Printer.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include "JSPrinter.h"
 #include "JSV8Engine.h"
 
 
@@ -12,11 +13,11 @@ namespace dev
 namespace eth
 {
 
-class JSV8Printer
+class JSV8Printer : public JSPrinter
 {
 public:
 	JSV8Printer(JSV8Engine const& _engine);
-	const char* print(v8::Handle const& _value) const;
+	const char* prettyPrint(JSV8Value const& _value) const;
 };
 
 }
diff --git a/test/libjsengine/JSV8Engine.cpp b/test/libjsengine/JSV8Engine.cpp
index b65f07d4d..da176bf88 100644
--- a/test/libjsengine/JSV8Engine.cpp
+++ b/test/libjsengine/JSV8Engine.cpp
@@ -4,6 +4,7 @@
 
 #include 
 #include 
+#include 
 
 using namespace std;
 using namespace dev;
@@ -13,22 +14,28 @@ BOOST_AUTO_TEST_SUITE(jsv8engine)
 
 BOOST_AUTO_TEST_CASE(evalInteger)
 {
-	JSV8Engine scope;
-	string result = scope.evaluate("1 + 1");
+	JSV8Engine engine;
+	JSV8Printer printer(engine);
+	auto value = engine.eval("1 + 1");
+	string result = printer.print(value);
 	BOOST_CHECK_EQUAL(result, "2");
 }
 
 BOOST_AUTO_TEST_CASE(evalString)
 {
-	JSV8Engine scope;
-	string result = scope.evaluate("'hello ' + 'world'");
+	JSV8Engine engine;
+	JSV8Printer printer(engine);
+	auto value = engine.eval("'hello ' + 'world'");
+	string result = printer.print(value);
 	BOOST_CHECK_EQUAL(result, "hello world");
 }
 
 BOOST_AUTO_TEST_CASE(evalEmpty)
 {
-	JSV8Engine scope;
-	string result = scope.evaluate("");
+	JSV8Engine engine;
+	JSV8Printer printer(engine);
+	auto value = engine.eval("");
+	string result = printer.print(value);
 	BOOST_CHECK_EQUAL(result, "undefined");
 }
 

From 299b994e7986e6249292560dc055e7f64b6c87e2 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Tue, 28 Apr 2015 14:17:10 +0200
Subject: [PATCH 05/87] simple repl working

---
 eth/CMakeLists.txt           |  2 ++
 eth/main.cpp                 | 14 ++++++++++++++
 libjsconsole/CMakeLists.txt  |  3 +++
 libjsconsole/JSConsole.cpp   | 27 +++++++++++++++++++++++++++
 libjsconsole/JSConsole.h     | 10 +++++++++-
 libjsconsole/JSV8Console.cpp | 20 --------------------
 libjsconsole/JSV8Console.h   | 29 -----------------------------
 libjsengine/JSPrinter.h      |  6 +++---
 libjsengine/JSV8Printer.h    |  2 +-
 9 files changed, 59 insertions(+), 54 deletions(-)
 delete mode 100644 libjsconsole/JSV8Console.cpp
 delete mode 100644 libjsconsole/JSV8Console.h

diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt
index 962d55373..2629befdd 100644
--- a/eth/CMakeLists.txt
+++ b/eth/CMakeLists.txt
@@ -6,6 +6,7 @@ aux_source_directory(. SRC_LIST)
 include_directories(BEFORE ..)
 include_directories(${Boost_INCLUDE_DIRS})
 include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
+include_directories(${V8_INCLUDE_DIRS})
 
 set(EXECUTABLE eth)
 
@@ -32,6 +33,7 @@ endif()
 
 target_link_libraries(${EXECUTABLE} webthree)
 target_link_libraries(${EXECUTABLE} ethash)
+target_link_libraries(${EXECUTABLE} jsconsole)
 
 if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
 	eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
diff --git a/eth/main.cpp b/eth/main.cpp
index 9c49396f0..5f1c464f3 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -38,6 +38,7 @@
 #include 
 #include 
 #include 
+#include 
 #if ETH_READLINE || !ETH_TRUE
 #include 
 #include 
@@ -406,6 +407,11 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
 
 int main(int argc, char** argv)
 {
+	JSConsole console;
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
 	cout << "\x1b[30mEthBlack\x1b[0m" << endl;
 	cout << "\x1b[90mEthCoal\x1b[0m" << endl;
 	cout << "\x1b[37mEthGray\x1b[0m" << endl;
@@ -1603,16 +1609,24 @@ int main(int argc, char** argv)
 		unsigned n =c->blockChain().details().number;
 		if (mining)
 			c->startMining();
+		JSConsole console;
 		while (!g_exit)
 		{
+			console.repl();
 			if ( c->isMining() &&c->blockChain().details().number - n == mining)
 				c->stopMining();
 			this_thread::sleep_for(chrono::milliseconds(100));
 		}
 	}
 	else
+	{
+		JSConsole console;
 		while (!g_exit)
+		{
+			console.repl();
 			this_thread::sleep_for(chrono::milliseconds(1000));
+		}
+	}
 
 	StructuredLogger::stopping(clientImplString, dev::Version);
 	auto netData = web3.saveNetwork();
diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt
index cac47fc6c..b67803dbf 100644
--- a/libjsconsole/CMakeLists.txt
+++ b/libjsconsole/CMakeLists.txt
@@ -12,6 +12,7 @@ aux_source_directory(. SRC_LIST)
 
 include_directories(BEFORE ..)
 include_directories(${V8_INCLUDE_DIRS})
+include_directories(${READLINE_INCLUDE_DIRS})
 
 set(EXECUTABLE jsconsole)
 
@@ -20,6 +21,8 @@ file(GLOB HEADERS "*.h")
 add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 
 target_link_libraries(${EXECUTABLE} jsengine)
+target_link_libraries(${EXECUTABLE} devcore)
+target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
 
 install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
 install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index 5ba1912ff..4ed6f6329 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -2,4 +2,31 @@
 // Created by Marek Kotewicz on 28/04/15.
 //
 
+#include 
+#include 
 #include "JSConsole.h"
+
+// TODO: readline!
+#include 
+#include 
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+
+int JSConsole::repl() const
+{
+	string cmd = "";
+	g_logPost = [](std::string const& a, char const*) { cout << "\r           \r" << a << endl << flush; rl_forced_update_display(); };
+
+	char* c = readline("> ");
+	if (c && *c)
+	{
+		cmd = string(c);
+		add_history(c);
+		auto value = m_engine.eval(cmd.c_str());
+		string result = m_printer.print(value);
+		free(c);
+		cout << result << endl;
+	}
+}
diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h
index 3e9124114..20ce986a2 100644
--- a/libjsconsole/JSConsole.h
+++ b/libjsconsole/JSConsole.h
@@ -4,6 +4,9 @@
 
 #pragma once
 
+#include 
+#include 
+
 namespace dev
 {
 namespace eth
@@ -12,7 +15,12 @@ namespace eth
 class JSConsole
 {
 public:
-	virtual void repl() const = 0;
+	JSConsole(): m_engine(), m_printer(m_engine) {}
+	int repl() const;
+
+private:
+	JSV8Engine m_engine;
+	JSV8Printer m_printer;
 };
 
 }
diff --git a/libjsconsole/JSV8Console.cpp b/libjsconsole/JSV8Console.cpp
deleted file mode 100644
index 7889b24c5..000000000
--- a/libjsconsole/JSV8Console.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Created by Marek Kotewicz on 28/04/15.
-//
-
-#include 
-#include 
-#include "JSV8Console.h"
-
-using namespace dev;
-using namespace dev::eth;
-
-JSV8Console::JSV8Console(): m_engine(), m_printer(m_engine)
-{
-
-}
-
-void JSV8Console::repl() const
-{
-
-}
diff --git a/libjsconsole/JSV8Console.h b/libjsconsole/JSV8Console.h
deleted file mode 100644
index 929a56f0b..000000000
--- a/libjsconsole/JSV8Console.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Created by Marek Kotewicz on 28/04/15.
-//
-
-#pragma once
-
-#include "JSConsole.h"
-
-namespace dev
-{
-namespace eth
-{
-
-class JSV8Engine;
-class JSV8Printer;
-
-class JSV8Console : public JSConsole
-{
-public:
-	JSV8Console();
-	void repl() const;
-
-private:
-	JSV8Engine m_engine;
-	JSV8Printer m_printer;
-};
-
-}
-}
diff --git a/libjsengine/JSPrinter.h b/libjsengine/JSPrinter.h
index bd0dd89b5..2450810fb 100644
--- a/libjsengine/JSPrinter.h
+++ b/libjsengine/JSPrinter.h
@@ -4,17 +4,17 @@
 
 #pragma once
 
-#include "JSEngine.h"
-
 namespace dev
 {
 namespace eth
 {
 
+template 
 class JSPrinter
 {
 public:
-	virtual const char* print(JSValue const& _value) const { return _value.asCString(); }
+	virtual const char* print(T const& _value) const { return _value.asCString(); }
+	virtual const char* prettyPrint(T const& _value) const { return print(_value); }
 };
 
 }
diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h
index e7bbfab9e..430842129 100644
--- a/libjsengine/JSV8Printer.h
+++ b/libjsengine/JSV8Printer.h
@@ -13,7 +13,7 @@ namespace dev
 namespace eth
 {
 
-class JSV8Printer : public JSPrinter
+class JSV8Printer : public JSPrinter
 {
 public:
 	JSV8Printer(JSV8Engine const& _engine);

From 31e5c13de4daa6bb9c9a777d098bc37dae0485f9 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Tue, 28 Apr 2015 15:10:00 +0200
Subject: [PATCH 06/87] jsconsole read nested objects

---
 eth/main.cpp               |  5 -----
 libjsconsole/JSConsole.cpp | 36 ++++++++++++++++++++++++++++++------
 libjsconsole/JSConsole.h   |  4 +++-
 3 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/eth/main.cpp b/eth/main.cpp
index 5f1c464f3..a31e7af3c 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -407,11 +407,6 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
 
 int main(int argc, char** argv)
 {
-	JSConsole console;
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
 	cout << "\x1b[30mEthBlack\x1b[0m" << endl;
 	cout << "\x1b[90mEthCoal\x1b[0m" << endl;
 	cout << "\x1b[37mEthGray\x1b[0m" << endl;
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index 4ed6f6329..8cbc91d54 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -3,6 +3,7 @@
 //
 
 #include 
+#include 
 #include 
 #include "JSConsole.h"
 
@@ -14,19 +15,42 @@ using namespace std;
 using namespace dev;
 using namespace dev::eth;
 
-int JSConsole::repl() const
+void JSConsole::repl() const
 {
 	string cmd = "";
 	g_logPost = [](std::string const& a, char const*) { cout << "\r           \r" << a << endl << flush; rl_forced_update_display(); };
 
-	char* c = readline("> ");
-	if (c && *c)
+	bool isEmpty = true;
+	int openBrackets = 0;
+	do {
+		char* buff = readline(promptForIndentionLevel(openBrackets).c_str());
+		isEmpty = !(buff && *buff);
+		if (!isEmpty)
+		{
+			cmd += string(buff);
+			cmd += " ";
+			free(buff);
+			int open = count(cmd.begin(), cmd.end(), '{');
+			open += count(cmd.begin(), cmd.end(), '(');
+			int closed = count(cmd.begin(), cmd.end(), '}');
+			closed += count(cmd.begin(), cmd.end(), ')');
+			openBrackets = open - closed;
+		}
+	} while (openBrackets > 0);
+
+	if (!isEmpty)
 	{
-		cmd = string(c);
-		add_history(c);
+		add_history(cmd.c_str());
 		auto value = m_engine.eval(cmd.c_str());
 		string result = m_printer.print(value);
-		free(c);
 		cout << result << endl;
 	}
 }
+
+std::string JSConsole::promptForIndentionLevel(int _i) const
+{
+	if (_i == 0)
+		return "> ";
+
+	return string((_i + 1) * 2, ' ');
+}
diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h
index 20ce986a2..216813a01 100644
--- a/libjsconsole/JSConsole.h
+++ b/libjsconsole/JSConsole.h
@@ -16,9 +16,11 @@ class JSConsole
 {
 public:
 	JSConsole(): m_engine(), m_printer(m_engine) {}
-	int repl() const;
+	void repl() const;
 
 private:
+	std::string promptForIndentionLevel(int _i) const;
+
 	JSV8Engine m_engine;
 	JSV8Printer m_printer;
 };

From 5cc56a72cb1d40d42bc1ba9e01f4ab91a5ca7aa8 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 29 Apr 2015 09:31:22 +0200
Subject: [PATCH 07/87] console command line option

---
 eth/main.cpp                             | 30 +++++++++++++++++-------
 test/libweb3jsonrpc/webthreestubclient.h | 30 ++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/eth/main.cpp b/eth/main.cpp
index 9b5e617b7..5892ecd70 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -179,6 +179,7 @@ void help()
 		<< "    -v,--verbosity <0 - 9>  Set the log verbosity from 0 to 9 (default: 8)." << endl
 		<< "    -V,--version  Show the version and exit." << endl
 		<< "    -h,--help  Show this help message and exit." << endl
+		<< "    --console Use interactive javascript console" << endl
 		;
 		exit(0);
 }
@@ -539,6 +540,9 @@ int main(int argc, char** argv)
 	unsigned benchmarkTrial = 3;
 	unsigned benchmarkTrials = 5;
 
+	// javascript console
+	bool useConsole = false;
+
 	/// Farm params
 	string farmURL = "http://127.0.0.1:8080";
 	unsigned farmRecheckPeriod = 500;
@@ -877,6 +881,8 @@ int main(int argc, char** argv)
 		else if (arg == "--json-rpc-port" && i + 1 < argc)
 			jsonrpc = atoi(argv[++i]);
 #endif
+		else if (arg == "--console")
+			useConsole = true;
 		else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
 			g_logVerbosity = atoi(argv[++i]);
 		else if ((arg == "-x" || arg == "--peers") && i + 1 < argc)
@@ -1611,21 +1617,29 @@ int main(int argc, char** argv)
 		unsigned n =c->blockChain().details().number;
 		if (mining)
 			c->startMining();
-		JSConsole console;
-		while (!g_exit)
+		if (useConsole)
 		{
-			console.repl();
-			if ( c->isMining() &&c->blockChain().details().number - n == mining)
-				c->stopMining();
-			this_thread::sleep_for(chrono::milliseconds(100));
+			JSConsole console;
+			while (!g_exit)
+			{
+				console.repl();
+				if (c->isMining() && c->blockChain().details().number - n == mining)
+					c->stopMining();
+				this_thread::sleep_for(chrono::milliseconds(100));
+			}
 		}
+		else
+			while (!g_exit)
+			{
+				if (c->isMining() && c->blockChain().details().number - n == mining)
+					c->stopMining();
+				this_thread::sleep_for(chrono::milliseconds(100));
+			}
 	}
 	else
 	{
-		JSConsole console;
 		while (!g_exit)
 		{
-			console.repl();
 			this_thread::sleep_for(chrono::milliseconds(1000));
 		}
 	}
diff --git a/test/libweb3jsonrpc/webthreestubclient.h b/test/libweb3jsonrpc/webthreestubclient.h
index fd71bfb5d..51d556eec 100644
--- a/test/libweb3jsonrpc/webthreestubclient.h
+++ b/test/libweb3jsonrpc/webthreestubclient.h
@@ -476,6 +476,36 @@ class WebThreeStubClient : public jsonrpc::Client
             else
                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
         }
+        std::string eth_signTransaction(const Json::Value& param1) throw (jsonrpc::JsonRpcException)
+        {
+            Json::Value p;
+            p.append(param1);
+            Json::Value result = this->CallMethod("eth_signTransaction",p);
+            if (result.isString())
+                return result.asString();
+            else
+                throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
+        }
+        Json::Value eth_inspectTransaction(const std::string& param1) throw (jsonrpc::JsonRpcException)
+        {
+            Json::Value p;
+            p.append(param1);
+            Json::Value result = this->CallMethod("eth_inspectTransaction",p);
+            if (result.isObject())
+                return result;
+            else
+                throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
+        }
+        bool eth_injectTransaction(const std::string& param1) throw (jsonrpc::JsonRpcException)
+        {
+            Json::Value p;
+            p.append(param1);
+            Json::Value result = this->CallMethod("eth_injectTransaction",p);
+            if (result.isBool())
+                return result.asBool();
+            else
+                throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
+        }
         bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException)
         {
             Json::Value p;

From d59944511da0c2b62f2e631ef682b0ed3ff610f2 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 29 Apr 2015 10:24:13 +0200
Subject: [PATCH 08/87] XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY for libjsengine

---
 libjsengine/CMakeLists.txt | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/libjsengine/CMakeLists.txt b/libjsengine/CMakeLists.txt
index 039e3d162..20de06d1d 100644
--- a/libjsengine/CMakeLists.txt
+++ b/libjsengine/CMakeLists.txt
@@ -8,10 +8,6 @@ endif()
 
 set(CMAKE_AUTOMOC OFF)
 
-# macos brew version of v8 needs to be compiled with libstdc++
-# it also needs to be dynamic library
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
-
 aux_source_directory(. SRC_LIST)
 
 include_directories(BEFORE ..)
@@ -23,6 +19,14 @@ file(GLOB HEADERS "*.h")
 
 add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 
+# macos brew version of v8 needs to be compiled with libstdc++
+# it also needs to be dynamic library
+# xcode needs libstdc++ to be explicitly set as it's attribute
+if (APPLE)
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
+	set_property(TARGET ${EXECUTABLE} PROPERTY XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libstdc++")
+endif()
+
 target_link_libraries(${EXECUTABLE} ${V8_LIBRARIES})
 
 install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )

From 5023f14c1bb7903eaf4e030ee7e80eba381bf7bd Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 00:57:58 +0200
Subject: [PATCH 09/87] fixes for eth_add_resources

---
 cmake/EthUtils.cmake          |  6 +++++-
 cmake/scripts/resource.cpp.in | 23 ----------------------
 cmake/scripts/resource.h.in   | 26 -------------------------
 cmake/scripts/resource.hpp.in | 36 +++++++++++++++++++++++++++++++++++
 cmake/scripts/resources.cmake | 10 ++++------
 5 files changed, 45 insertions(+), 56 deletions(-)
 delete mode 100644 cmake/scripts/resource.cpp.in
 delete mode 100644 cmake/scripts/resource.h.in
 create mode 100644 cmake/scripts/resource.hpp.in

diff --git a/cmake/EthUtils.cmake b/cmake/EthUtils.cmake
index 147ce0737..d5da866ea 100644
--- a/cmake/EthUtils.cmake
+++ b/cmake/EthUtils.cmake
@@ -64,7 +64,11 @@ endmacro()
 
 # Creates C resources file from files
 function(eth_add_resources TARGET RESOURCE_FILE)
-	add_custom_command(TARGET ${TARGET} PRE_BUILD
+
+	add_custom_target("${TARGET}.resources"
 		COMMAND ${CMAKE_COMMAND} -DETH_RES_FILE="${RESOURCE_FILE}" -P "${ETH_SCRIPTS_DIR}/resources.cmake"
 	)
+
+	add_dependencies(${TARGET} "${TARGET}.resources")
+
 endfunction()
diff --git a/cmake/scripts/resource.cpp.in b/cmake/scripts/resource.cpp.in
deleted file mode 100644
index b73a8df1a..000000000
--- a/cmake/scripts/resource.cpp.in
+++ /dev/null
@@ -1,23 +0,0 @@
-// this file is autogenerated, do not modify!!!
-
-#include 
-#include 
-#include "${ETH_RESOURCE_NAME}.h"
-
-using namespace std;
-using namespace dev;
-using namespace dev::eth;
-
-${ETH_RESOURCE_NAME}::${ETH_RESOURCE_NAME}()
-{
-${ETH_RESULT_DATA}
-${ETH_RESULT_INIT}
-}
-
-string ${ETH_RESOURCE_NAME}::loadResourceAsString(string _name)
-{
-	ostringstream bistream;
-	bistream.write(eth_resources[_name], eth_sizes[_name]);
-	return bistream.str();
-}
-
diff --git a/cmake/scripts/resource.h.in b/cmake/scripts/resource.h.in
deleted file mode 100644
index b27c3c882..000000000
--- a/cmake/scripts/resource.h.in
+++ /dev/null
@@ -1,26 +0,0 @@
-// this file is autogenerated, do not modify!!!
-#pragma once
-
-#include 
-#include 
-
-namespace dev
-{
-namespace eth
-{
-
-class ${ETH_RESOURCE_NAME}
-{
-public:
-	${ETH_RESOURCE_NAME}();
-	std::string loadResourceAsString(std::string _name):
-
-private:
-	std::unordered_map  m_resources;
-	std::unordered_map  m_sizes;
-
-};
-
-}
-}
-
diff --git a/cmake/scripts/resource.hpp.in b/cmake/scripts/resource.hpp.in
new file mode 100644
index 000000000..a8bbca377
--- /dev/null
+++ b/cmake/scripts/resource.hpp.in
@@ -0,0 +1,36 @@
+// this file is autogenerated, do not modify!!!
+#pragma once
+
+#include 
+#include 
+#include 
+
+namespace dev
+{
+namespace eth
+{
+
+class ${ETH_RESOURCE_NAME}
+{
+public:
+	${ETH_RESOURCE_NAME}()
+	{
+${ETH_RESULT_DATA}
+${ETH_RESULT_INIT}
+	}
+
+	std::string loadResourceAsString(std::string _name)
+	{
+		std::ostringstream bistream;
+		bistream.write(m_resources[_name], m_sizes[_name]);
+		return bistream.str();
+	}
+
+private:
+	std::map  m_resources;
+	std::map  m_sizes;
+};
+
+}
+}
+
diff --git a/cmake/scripts/resources.cmake b/cmake/scripts/resources.cmake
index d69d99e96..93326a257 100644
--- a/cmake/scripts/resources.cmake
+++ b/cmake/scripts/resources.cmake
@@ -44,17 +44,15 @@ foreach(resource ${ETH_RESOURCES})
 	set(ETH_RESULT_DATA "${ETH_RESULT_DATA}	static const unsigned char eth_${resource}[] = {\n	// ${filename}\n	${filedata}\n};\n")
 
 	# append init resources
-	set(ETH_RESULT_INIT "${ETH_RESULT_INIT}	eth_resources[\"${resource}\"] = (char const*)eth_${resource};\n")
-	set(ETH_RESULT_INIT "${ETH_RESULT_INIT}	eth_sizes[\"${resource}\"]     = sizeof(eth_${resource});\n")
+	set(ETH_RESULT_INIT "${ETH_RESULT_INIT}	m_resources[\"${resource}\"] = (char const*)eth_${resource};\n")
+	set(ETH_RESULT_INIT "${ETH_RESULT_INIT}	m_sizes[\"${resource}\"]     = sizeof(eth_${resource});\n")
 
 endforeach(resource)
 
 set(ETH_DST_NAME "${ETH_RESOURCE_LOCATION}/${ETH_RESOURCE_NAME}")
 
-configure_file("${CMAKE_CURRENT_LIST_DIR}/resource.cpp.in" "${ETH_DST_NAME}.cpp.tmp")
-configure_file("${CMAKE_CURRENT_LIST_DIR}/resource.h.in" "${ETH_DST_NAME}.h.tmp")
+configure_file("${CMAKE_CURRENT_LIST_DIR}/resource.hpp.in" "${ETH_DST_NAME}.hpp.tmp")
 
 include("${CMAKE_CURRENT_LIST_DIR}/../EthUtils.cmake")
-replace_if_different("${ETH_DST_NAME}.cpp.tmp" "${ETH_DST_NAME}.cpp")
-replace_if_different("${ETH_DST_NAME}.h.tmp" "${ETH_DST_NAME}.h")
+replace_if_different("${ETH_DST_NAME}.hpp.tmp" "${ETH_DST_NAME}.hpp")
 

From 152a60f4b3c79215d0569722be03db6e1586d7e8 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 00:58:54 +0200
Subject: [PATCH 10/87] first resources added using eth_add_resources

---
 libjsconsole/CMakeLists.txt    |  3 +++
 libjsconsole/JSConsole.cpp     | 11 +++++++++++
 libjsconsole/JSConsole.h       |  2 +-
 libjsconsole/JSResources.cmake |  7 +++++++
 libjsengine/JSV8Printer.cpp    |  1 -
 libjsengine/JSV8Printer.h      |  1 -
 6 files changed, 22 insertions(+), 3 deletions(-)
 create mode 100644 libjsconsole/JSResources.cmake

diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt
index b67803dbf..984874921 100644
--- a/libjsconsole/CMakeLists.txt
+++ b/libjsconsole/CMakeLists.txt
@@ -20,6 +20,9 @@ file(GLOB HEADERS "*.h")
 
 add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 
+include(EthUtils)
+eth_add_resources(${EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake")
+
 target_link_libraries(${EXECUTABLE} jsengine)
 target_link_libraries(${EXECUTABLE} devcore)
 target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index 8cbc91d54..91860422f 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -6,6 +6,7 @@
 #include 
 #include 
 #include "JSConsole.h"
+#include "libjsconsole/JSConsoleResources.hpp"
 
 // TODO: readline!
 #include 
@@ -15,6 +16,14 @@ using namespace std;
 using namespace dev;
 using namespace dev::eth;
 
+JSConsole::JSConsole(): m_engine(), m_printer(m_engine)
+{
+	JSConsoleResources resources;
+	string web3 = resources.loadResourceAsString("web3");
+	m_engine.eval(web3.c_str());
+	m_engine.eval("web3 = require('web3');");
+}
+
 void JSConsole::repl() const
 {
 	string cmd = "";
@@ -54,3 +63,5 @@ std::string JSConsole::promptForIndentionLevel(int _i) const
 
 	return string((_i + 1) * 2, ' ');
 }
+
+
diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h
index 216813a01..9c278a93d 100644
--- a/libjsconsole/JSConsole.h
+++ b/libjsconsole/JSConsole.h
@@ -15,7 +15,7 @@ namespace eth
 class JSConsole
 {
 public:
-	JSConsole(): m_engine(), m_printer(m_engine) {}
+	JSConsole();
 	void repl() const;
 
 private:
diff --git a/libjsconsole/JSResources.cmake b/libjsconsole/JSResources.cmake
new file mode 100644
index 000000000..c30d7614e
--- /dev/null
+++ b/libjsconsole/JSResources.cmake
@@ -0,0 +1,7 @@
+
+set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.min.js")
+
+set(ETH_RESOURCE_NAME "JSConsoleResources")
+set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}")
+set(ETH_RESOURCES "web3")
+
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index 80c06d590..3ac7d475b 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -9,7 +9,6 @@ using namespace eth;
 
 JSV8Printer::JSV8Printer(JSV8Engine const& _engine)
 {
-
 }
 
 const char* JSV8Printer::prettyPrint(JSV8Value const& _value) const
diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h
index 430842129..b35f0d746 100644
--- a/libjsengine/JSV8Printer.h
+++ b/libjsengine/JSV8Printer.h
@@ -7,7 +7,6 @@
 #include "JSPrinter.h"
 #include "JSV8Engine.h"
 
-
 namespace dev
 {
 namespace eth

From 1f4d0e32bf46c3aa3cfa9c8e1bfb012af3dc8eaf Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 01:40:22 +0200
Subject: [PATCH 11/87] pretty printing in js console in progress

---
 libjsengine/CMakeLists.txt    |  3 ++
 libjsengine/JSResources.cmake |  7 +++
 libjsengine/JSV8Printer.cpp   |  6 +++
 libjsengine/PrettyPrint.js    | 88 +++++++++++++++++++++++++++++++++++
 4 files changed, 104 insertions(+)
 create mode 100644 libjsengine/JSResources.cmake
 create mode 100644 libjsengine/PrettyPrint.js

diff --git a/libjsengine/CMakeLists.txt b/libjsengine/CMakeLists.txt
index 20de06d1d..eb90bff61 100644
--- a/libjsengine/CMakeLists.txt
+++ b/libjsengine/CMakeLists.txt
@@ -19,6 +19,9 @@ file(GLOB HEADERS "*.h")
 
 add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 
+include(EthUtils)
+eth_add_resources(${EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake")
+
 # macos brew version of v8 needs to be compiled with libstdc++
 # it also needs to be dynamic library
 # xcode needs libstdc++ to be explicitly set as it's attribute
diff --git a/libjsengine/JSResources.cmake b/libjsengine/JSResources.cmake
new file mode 100644
index 000000000..442bbcf6b
--- /dev/null
+++ b/libjsengine/JSResources.cmake
@@ -0,0 +1,7 @@
+
+set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js")
+
+set(ETH_RESOURCE_NAME "JSEngineResources")
+set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}")
+set(ETH_RESOURCES "pretty_print")
+
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index 3ac7d475b..14bc66315 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -2,13 +2,19 @@
 // Created by Marek Kotewicz on 28/04/15.
 //
 
+#include 
 #include "JSV8Printer.h"
+#include "libjsengine/JSEngineResources.hpp"
 
+using namespace std;
 using namespace dev;
 using namespace eth;
 
 JSV8Printer::JSV8Printer(JSV8Engine const& _engine)
 {
+	JSEngineResources resources;
+	string prettyPrint = resources.loadResourceAsString("pretty_print");
+	_engine.eval(prettyPrint.c_str());
 }
 
 const char* JSV8Printer::prettyPrint(JSV8Value const& _value) const
diff --git a/libjsengine/PrettyPrint.js b/libjsengine/PrettyPrint.js
new file mode 100644
index 000000000..f8b26f58a
--- /dev/null
+++ b/libjsengine/PrettyPrint.js
@@ -0,0 +1,88 @@
+var prettyPrint = (function () {
+    function pp(object, indent) {
+        try {
+            JSON.stringify(object)
+        } catch(e) {
+            return pp(e, indent);
+        }
+        var str = "";
+        if(object instanceof Array) {
+            str += "[";
+            for(var i = 0, l = object.length; i < l; i++) {
+                str += pp(object[i], indent);
+                if(i < l-1) {
+                    str += ", ";
+                }
+            }
+            str += " ]";
+        } else if (object instanceof Error) {
+            str += "\033[31m" + "Error:\033[0m " + object.message;
+        } else if (isBigNumber(object)) {
+            str += "\033[32m'" + object.toString(10) + "'";
+        } else if(typeof(object) === "object") {
+            str += "{\n";
+            indent += "  ";
+            var last = getFields(object).pop()
+            getFields(object).forEach(function (k) {
+                str += indent + k + ": ";
+                try {
+                    str += pp(object[k], indent);
+                } catch (e) {
+                    str += pp(e, indent);
+                }
+                if(k !== last) {
+                    str += ",";
+                }
+                str += "\n";
+            });
+            str += indent.substr(2, indent.length) + "}";
+        } else if(typeof(object) === "string") {
+            str += "\033[32m'" + object + "'";
+        } else if(typeof(object) === "undefined") {
+            str += "\033[1m\033[30m" + object;
+        } else if(typeof(object) === "number") {
+            str += "\033[31m" + object;
+        } else if(typeof(object) === "function") {
+            str += "\033[35m[Function]";
+        } else {
+            str += object;
+        }
+        str += "\033[0m";
+        return str;
+    }
+    var redundantFields = [
+        'valueOf',
+        'toString',
+        'toLocaleString',
+        'hasOwnProperty',
+        'isPrototypeOf',
+        'propertyIsEnumerable',
+        'constructor',
+        '__defineGetter__',
+        '__defineSetter__',
+        '__lookupGetter__',
+        '__lookupSetter__',
+        '__proto__'
+    ];
+    var getFields = function (object) {
+        var result = Object.getOwnPropertyNames(object);
+        if (object.constructor && object.constructor.prototype) {
+            result = result.concat(Object.getOwnPropertyNames(object.constructor.prototype));
+        }
+        return result.filter(function (field) {
+            return redundantFields.indexOf(field) === -1;
+        });
+    };
+    var isBigNumber = function (object) {
+        return typeof BigNumber !== 'undefined' && object instanceof BigNumber;
+    };
+    function prettyPrintInner(/* */) {
+        var args = arguments;
+        var ret = "";
+        for(var i = 0, l = args.length; i < l; i++) {
+    	    ret += pp(args[i], "") + "\n";
+        }
+        return ret;
+    };
+    return prettyPrintInner;
+})();

From 1055b10b30337550e4ed63b68ab9c177dda80a71 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 10:22:32 +0200
Subject: [PATCH 12/87] pretty printing

---
 libjsconsole/JSConsole.cpp  |  2 +-
 libjsengine/JSV8Engine.h    |  4 +---
 libjsengine/JSV8Printer.cpp | 12 +++++++++---
 libjsengine/JSV8Printer.h   |  2 ++
 4 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index 91860422f..8d69e7fb1 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -51,7 +51,7 @@ void JSConsole::repl() const
 	{
 		add_history(cmd.c_str());
 		auto value = m_engine.eval(cmd.c_str());
-		string result = m_printer.print(value);
+		string result = m_printer.prettyPrint(value);
 		cout << result << endl;
 	}
 }
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
index d020ebb95..1bb4e5f13 100644
--- a/libjsengine/JSV8Engine.h
+++ b/libjsengine/JSV8Engine.h
@@ -32,14 +32,12 @@ public:
 	JSV8Engine();
 	virtual ~JSV8Engine();
 	JSV8Value eval(const char* _cstr) const;
+	v8::Handle const& context() const;
 
 private:
 	static JSV8Env s_env;
 	v8::Isolate* m_isolate;
 	JSV8Scope* m_scope;
-
-protected:
-	v8::Handle const& context() const;
 };
 
 }
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index 14bc66315..9b1536fba 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -10,14 +10,20 @@ using namespace std;
 using namespace dev;
 using namespace eth;
 
-JSV8Printer::JSV8Printer(JSV8Engine const& _engine)
+JSV8Printer::JSV8Printer(JSV8Engine const& _engine): m_engine(_engine)
 {
 	JSEngineResources resources;
 	string prettyPrint = resources.loadResourceAsString("pretty_print");
-	_engine.eval(prettyPrint.c_str());
+	m_engine.eval(prettyPrint.c_str());
 }
 
 const char* JSV8Printer::prettyPrint(JSV8Value const& _value) const
 {
-	return nullptr;
+	v8::HandleScope handleScope(m_engine.context()->GetIsolate());
+	v8::Local pp = v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "prettyPrint");
+	v8::Handle func = v8::Handle::Cast(m_engine.context()->Global()->Get(pp));
+	v8::Local values[1] = {_value.value()};
+	v8::Local res = v8::Local::Cast(func->Call(func, 1, values));
+	v8::String::Utf8Value str(res);
+	return *str ? *str : "";
 }
diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h
index b35f0d746..55ea89431 100644
--- a/libjsengine/JSV8Printer.h
+++ b/libjsengine/JSV8Printer.h
@@ -17,6 +17,8 @@ class JSV8Printer : public JSPrinter
 public:
 	JSV8Printer(JSV8Engine const& _engine);
 	const char* prettyPrint(JSV8Value const& _value) const;
+private:
+	JSV8Engine const& m_engine;
 };
 
 }

From 367e977c21c51aa36242a418e8de9f21128a12fb Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 10:43:30 +0200
Subject: [PATCH 13/87] simplified loading string from eth resources

---
 cmake/scripts/resource.hpp.in | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/cmake/scripts/resource.hpp.in b/cmake/scripts/resource.hpp.in
index a8bbca377..6a9740616 100644
--- a/cmake/scripts/resource.hpp.in
+++ b/cmake/scripts/resource.hpp.in
@@ -2,7 +2,6 @@
 #pragma once
 
 #include 
-#include 
 #include 
 
 namespace dev
@@ -19,12 +18,7 @@ ${ETH_RESULT_DATA}
 ${ETH_RESULT_INIT}
 	}
 
-	std::string loadResourceAsString(std::string _name)
-	{
-		std::ostringstream bistream;
-		bistream.write(m_resources[_name], m_sizes[_name]);
-		return bistream.str();
-	}
+	std::string loadResourceAsString(std::string _name) { return std::string(m_resources[_name], m_sizes[_name]); }
 
 private:
 	std::map  m_resources;

From 2cbe6edd7aa8f1f9ce1aaf9368c9f54e55b44571 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 12:40:02 +0200
Subject: [PATCH 14/87] improved eth_add_resources

---
 cmake/EthUtils.cmake          | 19 ++++++++++++++-----
 cmake/scripts/resources.cmake |  1 -
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/cmake/EthUtils.cmake b/cmake/EthUtils.cmake
index d5da866ea..85d8c0dc4 100644
--- a/cmake/EthUtils.cmake
+++ b/cmake/EthUtils.cmake
@@ -63,12 +63,21 @@ macro(eth_add_test NAME)
 endmacro()
 
 # Creates C resources file from files
-function(eth_add_resources TARGET RESOURCE_FILE)
+function(eth_add_resources RESOURCE_FILE OUT_FILE)
+	include("${RESOURCE_FILE}")
+	set(OUTPUT  "${ETH_RESOURCE_LOCATION}/${ETH_RESOURCE_NAME}.hpp")
+	set(${OUT_FILE} "${OUTPUT}"  PARENT_SCOPE)
 
-	add_custom_target("${TARGET}.resources"
-		COMMAND ${CMAKE_COMMAND} -DETH_RES_FILE="${RESOURCE_FILE}" -P "${ETH_SCRIPTS_DIR}/resources.cmake"
-	)
+	set(filenames "${RESOURCE_FILE}")
+	list(APPEND filenames "${ETH_SCRIPTS_DIR}/resources.cmake")
+	foreach(resource ${ETH_RESOURCES})
+		list(APPEND filenames "${${resource}}")
+	endforeach(resource)
 
-	add_dependencies(${TARGET} "${TARGET}.resources")
+	message(STATUS "filenames; ${filenames}")
 
+	add_custom_command(OUTPUT ${OUTPUT}
+		COMMAND ${CMAKE_COMMAND} -DETH_RES_FILE="${RESOURCE_FILE}" -P "${ETH_SCRIPTS_DIR}/resources.cmake"
+		DEPENDS ${filenames}
+	)
 endfunction()
diff --git a/cmake/scripts/resources.cmake b/cmake/scripts/resources.cmake
index 93326a257..b0cadbf6d 100644
--- a/cmake/scripts/resources.cmake
+++ b/cmake/scripts/resources.cmake
@@ -55,4 +55,3 @@ configure_file("${CMAKE_CURRENT_LIST_DIR}/resource.hpp.in" "${ETH_DST_NAME}.hpp.
 
 include("${CMAKE_CURRENT_LIST_DIR}/../EthUtils.cmake")
 replace_if_different("${ETH_DST_NAME}.hpp.tmp" "${ETH_DST_NAME}.hpp")
-

From b8ab4a0d5d71a293a35a68d615708f86e0a99445 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 12:40:35 +0200
Subject: [PATCH 15/87] making everything work with new eth_add_resources

---
 libjsconsole/CMakeLists.txt   | 6 +++---
 libjsengine/CMakeLists.txt    | 6 +++---
 libjsengine/JSResources.cmake | 1 -
 libjsengine/JSV8Printer.cpp   | 1 +
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt
index 984874921..7fa3c5057 100644
--- a/libjsconsole/CMakeLists.txt
+++ b/libjsconsole/CMakeLists.txt
@@ -18,10 +18,10 @@ set(EXECUTABLE jsconsole)
 
 file(GLOB HEADERS "*.h")
 
-add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
-
 include(EthUtils)
-eth_add_resources(${EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake")
+eth_add_resources("${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake" JSRES)
+
+add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES})
 
 target_link_libraries(${EXECUTABLE} jsengine)
 target_link_libraries(${EXECUTABLE} devcore)
diff --git a/libjsengine/CMakeLists.txt b/libjsengine/CMakeLists.txt
index eb90bff61..d16d1b102 100644
--- a/libjsengine/CMakeLists.txt
+++ b/libjsengine/CMakeLists.txt
@@ -17,10 +17,10 @@ set(EXECUTABLE jsengine)
 
 file(GLOB HEADERS "*.h")
 
-add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
-
 include(EthUtils)
-eth_add_resources(${EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake")
+eth_add_resources("${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake" "JSRES")
+message(STATUS "HERE!!! ${JSRES}")
+add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES})
 
 # macos brew version of v8 needs to be compiled with libstdc++
 # it also needs to be dynamic library
diff --git a/libjsengine/JSResources.cmake b/libjsengine/JSResources.cmake
index 442bbcf6b..b0b5d0c1e 100644
--- a/libjsengine/JSResources.cmake
+++ b/libjsengine/JSResources.cmake
@@ -4,4 +4,3 @@ set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js")
 set(ETH_RESOURCE_NAME "JSEngineResources")
 set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}")
 set(ETH_RESOURCES "pretty_print")
-
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index 9b1536fba..87a53b6da 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -5,6 +5,7 @@
 #include 
 #include "JSV8Printer.h"
 #include "libjsengine/JSEngineResources.hpp"
+#include "libjsengine/t.h"
 
 using namespace std;
 using namespace dev;

From 8f8e07d287171d5deba8ae2d28256b00a3238ed5 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 13:20:14 +0200
Subject: [PATCH 16/87] make jsconsole optional global dependency

---
 CMakeLists.txt              | 15 +++++++++++++--
 cmake/EthDependencies.cmake |  9 ++++++---
 eth/CMakeLists.txt          | 10 ++++++++--
 eth/main.cpp                |  8 ++++++++
 4 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97d108e6c..dc3c1ec32 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,6 +40,7 @@ option(GUI "Build GUI components (AlethZero, Mix)" ON)
 option(TESTS "Build the tests." ON)
 option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
 option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
+option(JSCONSOLE "Build in javascript console" OFF)
 
 # propagates CMake configuration options to the compiler
 function(configureProject)
@@ -193,9 +194,14 @@ eth_format_option(GUI)
 eth_format_option(TESTS)
 eth_format_option(TOOLS)
 eth_format_option(ETHASHCL)
+eth_format_option(JSCONSOLE)
 eth_format_option_on_decent_platform(SERPENT)
 eth_format_option_on_decent_platform(NCURSES)
 
+if (JSCONSOLE)
+	set(JSONRPC ON)
+endif()
+
 if (GUI)
 	set(JSONRPC ON)
 endif()
@@ -284,6 +290,7 @@ message("-- GUI              Build GUI components                     ${GUI}")
 message("-- NCURSES          Build NCurses components                 ${NCURSES}")
 message("-- TESTS            Build tests                              ${TESTS}")
 message("-- ETHASHCL         Build OpenCL components (experimental!)  ${ETHASHCL}")
+message("-- JSCONSOLE        Build with javascript console            ${JSCONSOLE}")
 message("-- EVMJIT           Build LLVM-based JIT EVM (experimental!) ${EVMJIT}")
 message("------------------------------------------------------------------------")
 message("")
@@ -327,8 +334,11 @@ if (JSONRPC)
 	add_subdirectory(libweb3jsonrpc)
 endif()
 
-add_subdirectory(libjsengine)
-add_subdirectory(libjsconsole)
+if (JSCONSOLE)
+	add_subdirectory(libjsengine)
+	add_subdirectory(libjsconsole)
+endif()
+
 add_subdirectory(secp256k1)
 add_subdirectory(libp2p)
 add_subdirectory(libdevcrypto)
@@ -385,6 +395,7 @@ if (GUI)
 
 endif()
 
+
 #unset(TARGET_PLATFORM CACHE)
 
 if (WIN32)
diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake
index 1edc33b65..01564632f 100644
--- a/cmake/EthDependencies.cmake
+++ b/cmake/EthDependencies.cmake
@@ -47,9 +47,12 @@ find_package (LevelDB REQUIRED)
 message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}")
 message(" - LevelDB lib: ${LEVELDB_LIBRARIES}")
 
-find_package (v8 REQUIRED)
-message(" - v8 header: ${V8_INCLUDE_DIRS}")
-message(" - v8 lib   : ${V8_LIBRARIES}")
+if (JSCONSOLE)
+	find_package (v8 REQUIRED)
+	message(" - v8 header: ${V8_INCLUDE_DIRS}")
+	message(" - v8 lib   : ${V8_LIBRARIES}")
+	add_definitions(-DETH_JSCONSOLE)
+endif()
 
 # TODO the Jsoncpp package does not yet check for correct version number
 find_package (Jsoncpp 0.60 REQUIRED)
diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt
index 2629befdd..a2396b432 100644
--- a/eth/CMakeLists.txt
+++ b/eth/CMakeLists.txt
@@ -6,7 +6,10 @@ aux_source_directory(. SRC_LIST)
 include_directories(BEFORE ..)
 include_directories(${Boost_INCLUDE_DIRS})
 include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
-include_directories(${V8_INCLUDE_DIRS})
+
+if (JSCONSOLE)
+	include_directories(${V8_INCLUDE_DIRS})
+endif()
 
 set(EXECUTABLE eth)
 
@@ -33,7 +36,10 @@ endif()
 
 target_link_libraries(${EXECUTABLE} webthree)
 target_link_libraries(${EXECUTABLE} ethash)
-target_link_libraries(${EXECUTABLE} jsconsole)
+
+if (JSCONSOLE)
+	target_link_libraries(${EXECUTABLE} jsconsole)
+endif()
 
 if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
 	eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
diff --git a/eth/main.cpp b/eth/main.cpp
index 5892ecd70..f4ad03b0b 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -38,7 +38,9 @@
 #include 
 #include 
 #include 
+#if ETH_JSCONSOLE || !ETH_TRUE
 #include 
+#endif
 #if ETH_READLINE || !ETH_TRUE
 #include 
 #include 
@@ -179,7 +181,9 @@ void help()
 		<< "    -v,--verbosity <0 - 9>  Set the log verbosity from 0 to 9 (default: 8)." << endl
 		<< "    -V,--version  Show the version and exit." << endl
 		<< "    -h,--help  Show this help message and exit." << endl
+#if ETH_JSCONSOLE || !ETH_TRUE
 		<< "    --console Use interactive javascript console" << endl
+#endif
 		;
 		exit(0);
 }
@@ -881,8 +885,10 @@ int main(int argc, char** argv)
 		else if (arg == "--json-rpc-port" && i + 1 < argc)
 			jsonrpc = atoi(argv[++i]);
 #endif
+#if ETH_JSCONSOLE
 		else if (arg == "--console")
 			useConsole = true;
+#endif
 		else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
 			g_logVerbosity = atoi(argv[++i]);
 		else if ((arg == "-x" || arg == "--peers") && i + 1 < argc)
@@ -1619,6 +1625,7 @@ int main(int argc, char** argv)
 			c->startMining();
 		if (useConsole)
 		{
+#if ETH_JSCONSOLE
 			JSConsole console;
 			while (!g_exit)
 			{
@@ -1627,6 +1634,7 @@ int main(int argc, char** argv)
 					c->stopMining();
 				this_thread::sleep_for(chrono::milliseconds(100));
 			}
+#endif
 		}
 		else
 			while (!g_exit)

From 2fec0f01d3237b594f28aa8b6f3144ced392c6a5 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 13:27:55 +0200
Subject: [PATCH 17/87] jsconsole optional for tests

---
 test/CMakeLists.txt | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 349ca9800..39a235c58 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -25,7 +25,10 @@ add_subdirectory(libethereum)
 add_subdirectory(libevm)
 add_subdirectory(libnatspec)
 add_subdirectory(libp2p)
-add_subdirectory(libjsengine)
+
+if (JSCONSOLE)
+	add_subdirectory(libjsengine)
+endif()
 
 if (SOLIDITY)
 	add_subdirectory(libsolidity)
@@ -42,7 +45,10 @@ include_directories(BEFORE ..)
 include_directories(${Boost_INCLUDE_DIRS})
 include_directories(${CRYPTOPP_INCLUDE_DIRS})
 include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
-include_directories(${V8_INCLUDE_DIRS})
+
+if (JSCONSOLE)
+	include_directories(${V8_INCLUDE_DIRS})
+endif()
 
 # search for test names and create ctest tests
 enable_testing()
@@ -68,15 +74,22 @@ target_link_libraries(testeth ${CURL_LIBRARIES})
 target_link_libraries(testeth ethereum)
 target_link_libraries(testeth ethcore)
 target_link_libraries(testeth secp256k1)
-target_link_libraries(testeth jsengine)
+
+if (JSCONSOLE)
+	target_link_libraries(testeth jsengine)
+endif()
+
 if (SOLIDITY)
 	target_link_libraries(testeth solidity)
 endif ()
+
 target_link_libraries(testeth testutils)
+
 if (GUI AND NOT JUSTTESTS)
 	target_link_libraries(testeth webthree)
 	target_link_libraries(testeth natspec)
 endif()
+
 if (JSONRPC)
 	target_link_libraries(testeth web3jsonrpc)
 	target_link_libraries(testeth ${JSON_RPC_CPP_CLIENT_LIBRARIES})

From 80b81ea6c83931d30e29c6bc6c8f65d691f3eeb8 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Thu, 30 Apr 2015 17:40:17 +0200
Subject: [PATCH 18/87] printing v8 errors

---
 libjsengine/JSV8Engine.cpp      | 16 +++++++++++-----
 test/libjsengine/JSV8Engine.cpp | 27 +++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 2538fa409..60a2926c7 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -77,8 +77,14 @@ const char* JSV8Value::asCString() const
 		// TODO: handle exceptions
 		return "";
 	}
+
 	else if (m_value->IsUndefined())
 		return "undefined";
+//	else if (m_value->IsNativeError())
+//	{
+//		v8::String::Utf8Value str(m_value);
+//		return *str ? *str : "error";
+//	}
 	v8::String::Utf8Value str(m_value);
 	return *str ? *str : "";
 }
@@ -118,16 +124,16 @@ JSV8Engine::~JSV8Engine()
 JSV8Value JSV8Engine::eval(const char* _cstr) const
 {
 	v8::HandleScope handleScope(m_isolate);
-//	v8::TryCatch tryCatch;
+	v8::TryCatch tryCatch;
 	v8::Local source = v8::String::NewFromUtf8(context()->GetIsolate(), _cstr);
 	v8::Local name(v8::String::NewFromUtf8(context()->GetIsolate(), "(shell)"));
 	v8::ScriptOrigin origin(name);
 	v8::Handle script = v8::Script::Compile(source, &origin);
+	// Make sure to wrap the exception in a new handle because
+	// the handle returned from the TryCatch is destroyed
+	// TODO: improve this cause sometimes incorrect message is being sent!
 	if (script.IsEmpty())
-	{
-		// TODO: handle exceptions
-		return JSV8Value(v8::Handle());
-	}
+		return v8::Exception::Error(v8::Local::New(context()->GetIsolate(), tryCatch.Message()->Get()));
 
 	return JSV8Value(script->Run());
 }
diff --git a/test/libjsengine/JSV8Engine.cpp b/test/libjsengine/JSV8Engine.cpp
index da176bf88..7690d0bc0 100644
--- a/test/libjsengine/JSV8Engine.cpp
+++ b/test/libjsengine/JSV8Engine.cpp
@@ -39,4 +39,31 @@ BOOST_AUTO_TEST_CASE(evalEmpty)
 	BOOST_CHECK_EQUAL(result, "undefined");
 }
 
+BOOST_AUTO_TEST_CASE(evalAssignment)
+{
+	JSV8Engine engine;
+	JSV8Printer printer(engine);
+	auto value = engine.eval("x = 5");
+	string result = printer.print(value);
+	BOOST_CHECK_EQUAL(result, "5");
+}
+
+BOOST_AUTO_TEST_CASE(evalIncorrectExpression)
+{
+	JSV8Engine engine;
+	JSV8Printer printer(engine);
+	auto value = engine.eval("[");
+	string result = printer.print(value);
+	BOOST_CHECK_EQUAL(result, "Error: Uncaught SyntaxError: Unexpected end of input");
+}
+
+BOOST_AUTO_TEST_CASE(evalNull)
+{
+	JSV8Engine engine;
+	JSV8Printer printer(engine);
+	auto value = engine.eval("null");
+	string result = printer.print(value);
+	BOOST_CHECK_EQUAL(result, "null");
+}
+
 BOOST_AUTO_TEST_SUITE_END()

From 7d8d30c551598437d57b5398847405d2839441a9 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Mon, 4 May 2015 12:58:56 +0200
Subject: [PATCH 19/87] rpc provider in progress

---
 eth/main.cpp                    | 12 +++++
 libjsconsole/CMakeLists.txt     |  1 +
 libjsconsole/JSConsole.cpp      | 11 ++---
 libjsconsole/JSConsole.h        |  2 +
 libjsconsole/JSResources.cmake  |  2 +-
 libjsengine/Common.js           | 11 +++++
 libjsengine/JSResources.cmake   |  4 +-
 libjsengine/JSV8Engine.cpp      | 66 ++++++++++++++++++++++++++-
 libjsengine/JSV8Printer.cpp     |  1 -
 libjsengine/JSV8RPC.cpp         | 79 +++++++++++++++++++++++++++++++++
 libjsengine/JSV8RPC.h           | 33 ++++++++++++++
 libjsengine/PrettyPrint.js      |  2 +
 test/libjsengine/JSV8Engine.cpp |  2 +
 13 files changed, 216 insertions(+), 10 deletions(-)
 create mode 100644 libjsengine/Common.js
 create mode 100644 libjsengine/JSV8RPC.cpp
 create mode 100644 libjsengine/JSV8RPC.h

diff --git a/eth/main.cpp b/eth/main.cpp
index f4ad03b0b..1ead0e08d 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -412,6 +412,18 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
 
 int main(int argc, char** argv)
 {
+	JSConsole console;
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
+	console.repl();
 	cout << "\x1b[30mEthBlack\x1b[0m" << endl;
 	cout << "\x1b[90mEthCoal\x1b[0m" << endl;
 	cout << "\x1b[37mEthGray\x1b[0m" << endl;
diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt
index 7fa3c5057..f019cbccf 100644
--- a/libjsconsole/CMakeLists.txt
+++ b/libjsconsole/CMakeLists.txt
@@ -29,3 +29,4 @@ target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
 
 install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
 install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )
+
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index 8d69e7fb1..3c63d6330 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -16,12 +16,13 @@ using namespace std;
 using namespace dev;
 using namespace dev::eth;
 
-JSConsole::JSConsole(): m_engine(), m_printer(m_engine)
+JSConsole::JSConsole(): m_engine(), m_printer(m_engine), m_rpc(m_engine)
 {
-	JSConsoleResources resources;
-	string web3 = resources.loadResourceAsString("web3");
-	m_engine.eval(web3.c_str());
-	m_engine.eval("web3 = require('web3');");
+//	JSConsoleResources resources;
+//	string web3 = resources.loadResourceAsString("web3");
+//	m_engine.eval(web3.c_str());
+//	m_engine.eval("web3 = require('web3');");
+	m_rpc.StartListening();
 }
 
 void JSConsole::repl() const
diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h
index 9c278a93d..96008baa8 100644
--- a/libjsconsole/JSConsole.h
+++ b/libjsconsole/JSConsole.h
@@ -6,6 +6,7 @@
 
 #include 
 #include 
+#include 
 
 namespace dev
 {
@@ -23,6 +24,7 @@ private:
 
 	JSV8Engine m_engine;
 	JSV8Printer m_printer;
+	JSV8RPC m_rpc;
 };
 
 }
diff --git a/libjsconsole/JSResources.cmake b/libjsconsole/JSResources.cmake
index c30d7614e..889dd2f2b 100644
--- a/libjsconsole/JSResources.cmake
+++ b/libjsconsole/JSResources.cmake
@@ -1,5 +1,5 @@
 
-set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.min.js")
+set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js")
 
 set(ETH_RESOURCE_NAME "JSConsoleResources")
 set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}")
diff --git a/libjsengine/Common.js b/libjsengine/Common.js
new file mode 100644
index 000000000..3911409a7
--- /dev/null
+++ b/libjsengine/Common.js
@@ -0,0 +1,11 @@
+console = {};
+console.log = function () {
+};
+console.warn = function () {
+};
+console.error = function () {
+};
+
+setTimeout = function () {
+};
+
diff --git a/libjsengine/JSResources.cmake b/libjsengine/JSResources.cmake
index b0b5d0c1e..d4370a8da 100644
--- a/libjsengine/JSResources.cmake
+++ b/libjsengine/JSResources.cmake
@@ -1,6 +1,8 @@
 
+set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js")
 set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js")
+set(common "${CMAKE_CURRENT_LIST_DIR}/Common.js")
 
 set(ETH_RESOURCE_NAME "JSEngineResources")
 set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}")
-set(ETH_RESOURCES "pretty_print")
+set(ETH_RESOURCES "web3" "pretty_print" "common")
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 60a2926c7..355485153 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -5,7 +5,9 @@
 #include 
 #include 
 #include "JSV8Engine.h"
+#include "libjsengine/JSEngineResources.hpp"
 
+using namespace std;
 using namespace dev;
 using namespace dev::eth;
 
@@ -14,6 +16,48 @@ namespace dev
 namespace eth
 {
 
+static const char* toCString(const v8::String::Utf8Value& value) {
+	return *value ? *value : "";
+}
+
+// from https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
+static void reportException(v8::Isolate* isolate, v8::TryCatch* try_catch) {
+	v8::HandleScope handle_scope(isolate);
+	v8::String::Utf8Value exception(try_catch->Exception());
+	const char* exception_string = toCString(exception);
+	v8::Handle message = try_catch->Message();
+	if (message.IsEmpty()) {
+		// V8 didn't provide any extra information about this error; just
+		// print the exception.
+		fprintf(stderr, "%s\n", exception_string);
+	} else {
+		// Print (filename):(line number): (message).
+		v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
+		const char* filename_string = toCString(filename);
+		int linenum = message->GetLineNumber();
+		fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
+		// Print line of source code.
+		v8::String::Utf8Value sourceline(message->GetSourceLine());
+		const char* sourceline_string = toCString(sourceline);
+		fprintf(stderr, "%s\n", sourceline_string);
+		// Print wavy underline (GetUnderline is deprecated).
+		int start = message->GetStartColumn();
+		for (int i = 0; i < start; i++) {
+			fprintf(stderr, " ");
+		}
+		int end = message->GetEndColumn();
+		for (int i = start; i < end; i++) {
+			fprintf(stderr, "^");
+		}
+		fprintf(stderr, "\n");
+		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
+		if (stack_trace.length() > 0) {
+			const char* stack_trace_string = toCString(stack_trace);
+			fprintf(stderr, "%s\n", stack_trace_string);
+		}
+	}
+}
+
 class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
 public:
 	virtual void* Allocate(size_t length) {
@@ -113,7 +157,14 @@ JSV8Env::~JSV8Env()
 JSV8Engine::JSV8Engine():
 		m_isolate(v8::Isolate::New()),
 		m_scope(new JSV8Scope(m_isolate))
-{}
+{
+	JSEngineResources resources;
+	string common = resources.loadResourceAsString("common");
+	string web3 = resources.loadResourceAsString("web3");
+	eval(common.c_str());
+	eval(web3.c_str());
+	eval("web3 = require('web3');");
+}
 
 JSV8Engine::~JSV8Engine()
 {
@@ -133,9 +184,20 @@ JSV8Value JSV8Engine::eval(const char* _cstr) const
 	// the handle returned from the TryCatch is destroyed
 	// TODO: improve this cause sometimes incorrect message is being sent!
 	if (script.IsEmpty())
+	{
+		reportException(context()->GetIsolate(), &tryCatch);
 		return v8::Exception::Error(v8::Local::New(context()->GetIsolate(), tryCatch.Message()->Get()));
+	}
+
+	auto result = script->Run();
+
+	if (result.IsEmpty())
+	{
+		reportException(context()->GetIsolate(), &tryCatch);
+		return v8::Exception::Error(v8::Local::New(context()->GetIsolate(), tryCatch.Message()->Get()));
+	}
 
-	return JSV8Value(script->Run());
+	return result;
 }
 
 v8::Handle const& JSV8Engine::context() const
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index 87a53b6da..9b1536fba 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -5,7 +5,6 @@
 #include 
 #include "JSV8Printer.h"
 #include "libjsengine/JSEngineResources.hpp"
-#include "libjsengine/t.h"
 
 using namespace std;
 using namespace dev;
diff --git a/libjsengine/JSV8RPC.cpp b/libjsengine/JSV8RPC.cpp
new file mode 100644
index 000000000..72dbc12ca
--- /dev/null
+++ b/libjsengine/JSV8RPC.cpp
@@ -0,0 +1,79 @@
+//
+// Created by Marek Kotewicz on 04/05/15.
+//
+
+#include "libjsconsole/JSConsoleResources.hpp"
+#include "JSV8RPC.h"
+#include 
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+
+namespace dev
+{
+namespace eth
+{
+
+void JSV8RPCSend(v8::FunctionCallbackInfo const& args)
+{
+	const char* tmp = R"(
+	{
+		"id": 1,
+				"jsonrpc": "2.0",
+				"result": "0x9df33b35fbdd8dff5e557a0cce288614dbf7327c292f1ac5b9c6c0e672005f48"
+	}
+	)";
+
+	v8::Local JSON = v8::String::NewFromUtf8(args.GetIsolate(), "JSON");
+	v8::Local parse = v8::String::NewFromUtf8(args.GetIsolate(), "parse");
+	v8::Handle jsonObject = v8::Handle::Cast(args.GetIsolate()->GetCurrentContext()->Global()->Get(JSON));
+	v8::Handle func = v8::Handle::Cast(jsonObject->Get(parse));
+
+	v8::Local values[1] = {v8::String::NewFromUtf8(args.GetIsolate(), tmp)};
+	args.GetReturnValue().Set(func->Call(func, 1, values));
+}
+
+}
+}
+
+JSV8RPC::JSV8RPC(JSV8Engine const &_engine): m_engine(_engine) {}
+
+JSV8RPC::~JSV8RPC()
+{
+	StopListening();
+}
+
+bool JSV8RPC::StartListening()
+{
+	v8::HandleScope scope(m_engine.context()->GetIsolate());
+	v8::Local rpcTemplate = v8::ObjectTemplate::New(m_engine.context()->GetIsolate());
+	rpcTemplate->SetInternalFieldCount(1);
+	rpcTemplate->Set(v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "send"),
+	                 v8::FunctionTemplate::New(m_engine.context()->GetIsolate(), JSV8RPCSend));
+	rpcTemplate->Set(v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "sendAsync"),
+	                 v8::FunctionTemplate::New(m_engine.context()->GetIsolate(), JSV8RPCSend));
+
+	v8::Local obj = rpcTemplate->NewInstance();
+	obj->SetInternalField(0, v8::External::New(m_engine.context()->GetIsolate(), this));
+
+	v8::Local web3 = v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "web3");
+	v8::Local setProvider = v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "setProvider");
+	v8::Handle web3object = v8::Handle::Cast(m_engine.context()->Global()->Get(web3));
+	v8::Handle func = v8::Handle::Cast(web3object->Get(setProvider));
+	v8::Local values[1] = {obj};
+	func->Call(func, 1, values);
+	return true;
+}
+
+bool JSV8RPC::StopListening()
+{
+	return true;
+}
+
+bool JSV8RPC::SendResponse(std::string const &_response, void *_addInfo)
+{
+	m_lastResponse = _response;
+	(void)_addInfo;
+	return true;
+}
diff --git a/libjsengine/JSV8RPC.h b/libjsengine/JSV8RPC.h
new file mode 100644
index 000000000..36591ee01
--- /dev/null
+++ b/libjsengine/JSV8RPC.h
@@ -0,0 +1,33 @@
+//
+// Created by Marek Kotewicz on 04/05/15.
+//
+
+#pragma once
+
+//#include 
+#include 
+
+namespace dev
+{
+namespace eth
+{
+
+class JSV8RPC
+{
+public:
+	JSV8RPC(JSV8Engine const& _engine);
+	virtual ~JSV8RPC();
+
+	bool StartListening();
+
+	bool StopListening();
+
+	bool SendResponse(std::string const& _response, void* _addInfo = NULL);
+
+private:
+	JSV8Engine const& m_engine;
+	std::string m_lastResponse;
+};
+
+}
+}
diff --git a/libjsengine/PrettyPrint.js b/libjsengine/PrettyPrint.js
index f8b26f58a..3957ac7aa 100644
--- a/libjsengine/PrettyPrint.js
+++ b/libjsengine/PrettyPrint.js
@@ -17,6 +17,8 @@ var prettyPrint = (function () {
             str += " ]";
         } else if (object instanceof Error) {
             str += "\033[31m" + "Error:\033[0m " + object.message;
+        }  else if (object === null) {
+            str += "\033[1m\033[30m" + "null";
         } else if (isBigNumber(object)) {
             str += "\033[32m'" + object.toString(10) + "'";
         } else if(typeof(object) === "object") {
diff --git a/test/libjsengine/JSV8Engine.cpp b/test/libjsengine/JSV8Engine.cpp
index 7690d0bc0..2f319ab71 100644
--- a/test/libjsengine/JSV8Engine.cpp
+++ b/test/libjsengine/JSV8Engine.cpp
@@ -63,7 +63,9 @@ BOOST_AUTO_TEST_CASE(evalNull)
 	JSV8Printer printer(engine);
 	auto value = engine.eval("null");
 	string result = printer.print(value);
+	string prettyResult = printer.prettyPrint(value);
 	BOOST_CHECK_EQUAL(result, "null");
+	BOOST_CHECK_EQUAL(prettyResult.find("null") != std::string::npos, true);
 }
 
 BOOST_AUTO_TEST_SUITE_END()

From a0f3c42d609d92bbc9d9e3ca0457ce1841c2ea26 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Mon, 4 May 2015 14:07:43 +0200
Subject: [PATCH 20/87] jsv8provider

---
 eth/main.cpp                   | 14 +--------
 libjsconsole/CMakeLists.txt    |  3 +-
 libjsconsole/JSConsole.cpp     | 14 ++++-----
 libjsconsole/JSConsole.h       |  7 +++--
 libjsconsole/JSV8Connector.cpp | 36 +++++++++++++++++++++++
 libjsconsole/JSV8Connector.h   | 30 +++++++++++++++++++
 libjsengine/JSV8RPC.cpp        | 53 ++++++++++++++--------------------
 libjsengine/JSV8RPC.h          | 10 ++-----
 8 files changed, 102 insertions(+), 65 deletions(-)
 create mode 100644 libjsconsole/JSV8Connector.cpp
 create mode 100644 libjsconsole/JSV8Connector.h

diff --git a/eth/main.cpp b/eth/main.cpp
index 1ead0e08d..f1b2c0358 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -412,18 +412,6 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
 
 int main(int argc, char** argv)
 {
-	JSConsole console;
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
-	console.repl();
 	cout << "\x1b[30mEthBlack\x1b[0m" << endl;
 	cout << "\x1b[90mEthCoal\x1b[0m" << endl;
 	cout << "\x1b[37mEthGray\x1b[0m" << endl;
@@ -1638,7 +1626,7 @@ int main(int argc, char** argv)
 		if (useConsole)
 		{
 #if ETH_JSCONSOLE
-			JSConsole console;
+			JSConsole console(web3, vector({sigKey}));
 			while (!g_exit)
 			{
 				console.repl();
diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt
index f019cbccf..932cd20dd 100644
--- a/libjsconsole/CMakeLists.txt
+++ b/libjsconsole/CMakeLists.txt
@@ -13,6 +13,7 @@ aux_source_directory(. SRC_LIST)
 include_directories(BEFORE ..)
 include_directories(${V8_INCLUDE_DIRS})
 include_directories(${READLINE_INCLUDE_DIRS})
+include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
 
 set(EXECUTABLE jsconsole)
 
@@ -26,7 +27,7 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES})
 target_link_libraries(${EXECUTABLE} jsengine)
 target_link_libraries(${EXECUTABLE} devcore)
 target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
+target_link_libraries(${EXECUTABLE} web3jsonrpc)
 
 install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
 install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )
-
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index 3c63d6330..ec9d05948 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -3,26 +3,24 @@
 //
 
 #include 
-#include 
 #include 
 #include "JSConsole.h"
+#include "JSV8Connector.h"
 #include "libjsconsole/JSConsoleResources.hpp"
 
 // TODO: readline!
 #include 
-#include 
 
 using namespace std;
 using namespace dev;
 using namespace dev::eth;
 
-JSConsole::JSConsole(): m_engine(), m_printer(m_engine), m_rpc(m_engine)
+JSConsole::JSConsole(WebThreeDirect& _web3, std::vector const& _accounts):
+		m_engine(),
+		m_printer(m_engine)
 {
-//	JSConsoleResources resources;
-//	string web3 = resources.loadResourceAsString("web3");
-//	m_engine.eval(web3.c_str());
-//	m_engine.eval("web3 = require('web3');");
-	m_rpc.StartListening();
+	m_jsonrpcConnector.reset(new JSV8Connector(m_engine));
+	m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts));
 }
 
 void JSConsole::repl() const
diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h
index 96008baa8..5112b056d 100644
--- a/libjsconsole/JSConsole.h
+++ b/libjsconsole/JSConsole.h
@@ -6,7 +6,7 @@
 
 #include 
 #include 
-#include 
+#include 
 
 namespace dev
 {
@@ -16,7 +16,7 @@ namespace eth
 class JSConsole
 {
 public:
-	JSConsole();
+	JSConsole(WebThreeDirect& _web3, std::vector const& _accounts);
 	void repl() const;
 
 private:
@@ -24,7 +24,8 @@ private:
 
 	JSV8Engine m_engine;
 	JSV8Printer m_printer;
-	JSV8RPC m_rpc;
+	std::unique_ptr m_jsonrpcServer;
+	std::unique_ptr m_jsonrpcConnector;
 };
 
 }
diff --git a/libjsconsole/JSV8Connector.cpp b/libjsconsole/JSV8Connector.cpp
new file mode 100644
index 000000000..1d43e7cd2
--- /dev/null
+++ b/libjsconsole/JSV8Connector.cpp
@@ -0,0 +1,36 @@
+//
+// Created by Marek Kotewicz on 04/05/15.
+//
+
+#include "JSV8Connector.h"
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+
+bool JSV8Connector::StartListening()
+{
+	return true;
+}
+
+bool JSV8Connector::StopListening()
+{
+	return true;
+}
+
+bool JSV8Connector::SendResponse(std::string const &_response, void *_addInfo)
+{
+	(void)_addInfo;
+	m_lastResponse = _response.c_str();
+	return true;
+}
+
+void JSV8Connector::onSend(const char *payload)
+{
+	OnRequest(payload, NULL);
+}
+
+JSV8Connector::~JSV8Connector()
+{
+	StopListening();
+}
diff --git a/libjsconsole/JSV8Connector.h b/libjsconsole/JSV8Connector.h
new file mode 100644
index 000000000..d76aa8d1c
--- /dev/null
+++ b/libjsconsole/JSV8Connector.h
@@ -0,0 +1,30 @@
+//
+// Created by Marek Kotewicz on 04/05/15.
+//
+
+#pragma once
+
+#include 
+#include 
+
+namespace dev
+{
+namespace eth
+{
+
+class JSV8Connector : public jsonrpc::AbstractServerConnector, public JSV8RPC
+{
+
+public:
+	JSV8Connector(JSV8Engine const &_engine) : JSV8RPC(_engine) {}
+	virtual ~JSV8Connector();
+
+	bool StartListening();
+	bool StopListening();
+	bool SendResponse(std::string const& _response, void* _addInfo = NULL);
+
+	void onSend(const char* payload);
+};
+
+}
+}
diff --git a/libjsengine/JSV8RPC.cpp b/libjsengine/JSV8RPC.cpp
index 72dbc12ca..8ce7c81d0 100644
--- a/libjsengine/JSV8RPC.cpp
+++ b/libjsengine/JSV8RPC.cpp
@@ -4,7 +4,6 @@
 
 #include "libjsconsole/JSConsoleResources.hpp"
 #include "JSV8RPC.h"
-#include 
 
 using namespace std;
 using namespace dev;
@@ -17,34 +16,29 @@ namespace eth
 
 void JSV8RPCSend(v8::FunctionCallbackInfo const& args)
 {
-	const char* tmp = R"(
-	{
-		"id": 1,
-				"jsonrpc": "2.0",
-				"result": "0x9df33b35fbdd8dff5e557a0cce288614dbf7327c292f1ac5b9c6c0e672005f48"
-	}
-	)";
-
 	v8::Local JSON = v8::String::NewFromUtf8(args.GetIsolate(), "JSON");
 	v8::Local parse = v8::String::NewFromUtf8(args.GetIsolate(), "parse");
+	v8::Local stringify = v8::String::NewFromUtf8(args.GetIsolate(), "stringify");
 	v8::Handle jsonObject = v8::Handle::Cast(args.GetIsolate()->GetCurrentContext()->Global()->Get(JSON));
-	v8::Handle func = v8::Handle::Cast(jsonObject->Get(parse));
+	v8::Handle parseFunc = v8::Handle::Cast(jsonObject->Get(parse));
+	v8::Handle stringifyFunc = v8::Handle::Cast(jsonObject->Get(stringify));
 
-	v8::Local values[1] = {v8::String::NewFromUtf8(args.GetIsolate(), tmp)};
-	args.GetReturnValue().Set(func->Call(func, 1, values));
-}
+	v8::Local self = args.Holder();
+	v8::Local wrap = v8::Local::Cast(self->GetInternalField(0));
+	JSV8RPC* that = static_cast(wrap->Value());
+	v8::Local vals[1] = {args[0]->ToObject()};
+	v8::Local stringifiedArg = stringifyFunc->Call(stringifyFunc, 1, vals);
+	v8::String::Utf8Value str(stringifiedArg);
+	that->onSend(*str);
 
+	v8::Local values[1] = {v8::String::NewFromUtf8(args.GetIsolate(), that->m_lastResponse)};
+	args.GetReturnValue().Set(parseFunc->Call(parseFunc, 1, values));
 }
-}
-
-JSV8RPC::JSV8RPC(JSV8Engine const &_engine): m_engine(_engine) {}
 
-JSV8RPC::~JSV8RPC()
-{
-	StopListening();
+}
 }
 
-bool JSV8RPC::StartListening()
+JSV8RPC::JSV8RPC(JSV8Engine const &_engine): m_engine(_engine)
 {
 	v8::HandleScope scope(m_engine.context()->GetIsolate());
 	v8::Local rpcTemplate = v8::ObjectTemplate::New(m_engine.context()->GetIsolate());
@@ -63,17 +57,12 @@ bool JSV8RPC::StartListening()
 	v8::Handle func = v8::Handle::Cast(web3object->Get(setProvider));
 	v8::Local values[1] = {obj};
 	func->Call(func, 1, values);
-	return true;
-}
 
-bool JSV8RPC::StopListening()
-{
-	return true;
-}
-
-bool JSV8RPC::SendResponse(std::string const &_response, void *_addInfo)
-{
-	m_lastResponse = _response;
-	(void)_addInfo;
-	return true;
+	m_lastResponse = R"(
+	{
+		"id": 1,
+		"jsonrpc": "2.0",
+		"error": "Uninitalized JSV8RPC!"
+	}
+	)";
 }
diff --git a/libjsengine/JSV8RPC.h b/libjsengine/JSV8RPC.h
index 36591ee01..25e671ab6 100644
--- a/libjsengine/JSV8RPC.h
+++ b/libjsengine/JSV8RPC.h
@@ -4,7 +4,6 @@
 
 #pragma once
 
-//#include 
 #include 
 
 namespace dev
@@ -16,17 +15,12 @@ class JSV8RPC
 {
 public:
 	JSV8RPC(JSV8Engine const& _engine);
-	virtual ~JSV8RPC();
 
-	bool StartListening();
-
-	bool StopListening();
-
-	bool SendResponse(std::string const& _response, void* _addInfo = NULL);
+	virtual void onSend(const char* _payload) = 0;
+	const char* m_lastResponse;
 
 private:
 	JSV8Engine const& m_engine;
-	std::string m_lastResponse;
 };
 
 }

From 6e6c6a82a454ce864faeb91971d58e2da9b975ed Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Mon, 4 May 2015 14:12:14 +0200
Subject: [PATCH 21/87] fixed printing bignumbers

---
 libjsengine/PrettyPrint.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libjsengine/PrettyPrint.js b/libjsengine/PrettyPrint.js
index 3957ac7aa..167c36aa6 100644
--- a/libjsengine/PrettyPrint.js
+++ b/libjsengine/PrettyPrint.js
@@ -76,7 +76,8 @@ var prettyPrint = (function () {
         });
     };
     var isBigNumber = function (object) {
-        return typeof BigNumber !== 'undefined' && object instanceof BigNumber;
+        return (!!object.constructor && object.constructor.name === 'BigNumber') ||
+            (typeof BigNumber !== 'undefined' && object instanceof BigNumber)
     };
     function prettyPrintInner(/* */) {
         var args = arguments;

From 6dda59e172ce0cf546df8ffed6a8b8bb5e28e7d3 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Mon, 4 May 2015 14:20:03 +0200
Subject: [PATCH 22/87] fixed license

---
 libjsconsole/JSConsole.cpp     | 24 +++++++++++++++++++++---
 libjsconsole/JSConsole.h       | 24 +++++++++++++++++++++---
 libjsconsole/JSV8Connector.cpp | 24 +++++++++++++++++++++---
 libjsconsole/JSV8Connector.h   | 24 +++++++++++++++++++++---
 libjsengine/JSEngine.cpp       | 24 +++++++++++++++++++++---
 libjsengine/JSEngine.h         | 24 +++++++++++++++++++++---
 libjsengine/JSPrinter.cpp      | 24 +++++++++++++++++++++---
 libjsengine/JSPrinter.h        | 24 +++++++++++++++++++++---
 libjsengine/JSV8Engine.cpp     | 24 +++++++++++++++++++++---
 libjsengine/JSV8Engine.h       | 24 +++++++++++++++++++++---
 libjsengine/JSV8Printer.cpp    | 24 +++++++++++++++++++++---
 libjsengine/JSV8Printer.h      | 24 +++++++++++++++++++++---
 libjsengine/JSV8RPC.cpp        | 24 +++++++++++++++++++++---
 libjsengine/JSV8RPC.h          | 24 +++++++++++++++++++++---
 14 files changed, 294 insertions(+), 42 deletions(-)

diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index ec9d05948..284fba4e3 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 28/04/15.
-//
+/*
+	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 JSConsole.cpp
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #include 
 #include 
diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h
index 5112b056d..895aa9130 100644
--- a/libjsconsole/JSConsole.h
+++ b/libjsconsole/JSConsole.h
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 28/04/15.
-//
+/*
+	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 JSConsole.h
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #pragma once
 
diff --git a/libjsconsole/JSV8Connector.cpp b/libjsconsole/JSV8Connector.cpp
index 1d43e7cd2..21295bec0 100644
--- a/libjsconsole/JSV8Connector.cpp
+++ b/libjsconsole/JSV8Connector.cpp
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 04/05/15.
-//
+/*
+	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 JSV8Connector.cpp
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #include "JSV8Connector.h"
 
diff --git a/libjsconsole/JSV8Connector.h b/libjsconsole/JSV8Connector.h
index d76aa8d1c..5ad9c177c 100644
--- a/libjsconsole/JSV8Connector.h
+++ b/libjsconsole/JSV8Connector.h
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 04/05/15.
-//
+/*
+	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 JSV8Connector.h
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #pragma once
 
diff --git a/libjsengine/JSEngine.cpp b/libjsengine/JSEngine.cpp
index 45898cacd..47afbd34e 100644
--- a/libjsengine/JSEngine.cpp
+++ b/libjsengine/JSEngine.cpp
@@ -1,5 +1,23 @@
-//
-// Created by Marek Kotewicz on 27/04/15.
-//
+/*
+	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 JSEngine.cpp
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #include "JSEngine.h"
diff --git a/libjsengine/JSEngine.h b/libjsengine/JSEngine.h
index 69d13d386..7df55c2f5 100644
--- a/libjsengine/JSEngine.h
+++ b/libjsengine/JSEngine.h
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 27/04/15.
-//
+/*
+	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 JSEngine.h
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #pragma once
 
diff --git a/libjsengine/JSPrinter.cpp b/libjsengine/JSPrinter.cpp
index fbd075fe2..35e315a78 100644
--- a/libjsengine/JSPrinter.cpp
+++ b/libjsengine/JSPrinter.cpp
@@ -1,5 +1,23 @@
-//
-// Created by Marek Kotewicz on 28/04/15.
-//
+/*
+	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 JSPrinter.cpp
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #include "JSPrinter.h"
diff --git a/libjsengine/JSPrinter.h b/libjsengine/JSPrinter.h
index 2450810fb..173ac2c87 100644
--- a/libjsengine/JSPrinter.h
+++ b/libjsengine/JSPrinter.h
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 28/04/15.
-//
+/*
+	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 JSPrinter.h
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #pragma once
 
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 355485153..90eef1b46 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 27/04/15.
-//
+/*
+	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 JSV8Engine.cpp
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #include 
 #include 
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
index 1bb4e5f13..7af72a8fe 100644
--- a/libjsengine/JSV8Engine.h
+++ b/libjsengine/JSV8Engine.h
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 27/04/15.
-//
+/*
+	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 JSV8Engine.h
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #pragma once
 
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index 9b1536fba..0c7cbb3e0 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 28/04/15.
-//
+/*
+	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 JSV8Printer.cpp
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #include 
 #include "JSV8Printer.h"
diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h
index 55ea89431..b02b025f8 100644
--- a/libjsengine/JSV8Printer.h
+++ b/libjsengine/JSV8Printer.h
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 28/04/15.
-//
+/*
+	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 JSV8Printer.h
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #pragma once
 
diff --git a/libjsengine/JSV8RPC.cpp b/libjsengine/JSV8RPC.cpp
index 8ce7c81d0..688bdb50f 100644
--- a/libjsengine/JSV8RPC.cpp
+++ b/libjsengine/JSV8RPC.cpp
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 04/05/15.
-//
+/*
+	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 JSV8RPC.cpp
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #include "libjsconsole/JSConsoleResources.hpp"
 #include "JSV8RPC.h"
diff --git a/libjsengine/JSV8RPC.h b/libjsengine/JSV8RPC.h
index 25e671ab6..a9bef8530 100644
--- a/libjsengine/JSV8RPC.h
+++ b/libjsengine/JSV8RPC.h
@@ -1,6 +1,24 @@
-//
-// Created by Marek Kotewicz on 04/05/15.
-//
+/*
+	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 JSV8RPC.h
+ * @author Marek Kotewicz 
+ * @date 2015
+ * Ethereum client.
+ */
 
 #pragma once
 

From f87fdaaa68cffaa54e295fb6712f95690114051b Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Mon, 4 May 2015 14:49:07 +0200
Subject: [PATCH 23/87] little cleanup

---
 libjsengine/JSV8Engine.cpp | 49 +++++++++++++++++++-------------------
 libjsengine/JSV8RPC.cpp    |  2 +-
 libjsengine/JSV8RPC.h      |  6 +++--
 3 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 90eef1b46..a19199dce 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -34,42 +34,52 @@ namespace dev
 namespace eth
 {
 
-static const char* toCString(const v8::String::Utf8Value& value) {
+static const char* toCString(v8::String::Utf8Value const& value)
+{
 	return *value ? *value : "";
 }
 
 // from https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
-static void reportException(v8::Isolate* isolate, v8::TryCatch* try_catch) {
+static void reportException(v8::Isolate* isolate, v8::TryCatch* try_catch)
+{
 	v8::HandleScope handle_scope(isolate);
 	v8::String::Utf8Value exception(try_catch->Exception());
 	const char* exception_string = toCString(exception);
 	v8::Handle message = try_catch->Message();
-	if (message.IsEmpty()) {
-		// V8 didn't provide any extra information about this error; just
-		// print the exception.
+
+	// V8 didn't provide any extra information about this error; just
+	// print the exception.
+	if (message.IsEmpty())
 		fprintf(stderr, "%s\n", exception_string);
-	} else {
+	else
+	{
 		// Print (filename):(line number): (message).
 		v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
 		const char* filename_string = toCString(filename);
 		int linenum = message->GetLineNumber();
 		fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
+
 		// Print line of source code.
 		v8::String::Utf8Value sourceline(message->GetSourceLine());
 		const char* sourceline_string = toCString(sourceline);
 		fprintf(stderr, "%s\n", sourceline_string);
+
 		// Print wavy underline (GetUnderline is deprecated).
 		int start = message->GetStartColumn();
-		for (int i = 0; i < start; i++) {
+
+		for (int i = 0; i < start; i++)
 			fprintf(stderr, " ");
-		}
+
 		int end = message->GetEndColumn();
-		for (int i = start; i < end; i++) {
+
+		for (int i = start; i < end; i++)
 			fprintf(stderr, "^");
-		}
+
 		fprintf(stderr, "\n");
 		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
-		if (stack_trace.length() > 0) {
+
+		if (stack_trace.length() > 0)
+		{
 			const char* stack_trace_string = toCString(stack_trace);
 			fprintf(stderr, "%s\n", stack_trace_string);
 		}
@@ -101,10 +111,6 @@ v8::Handle createShellContext(v8::Isolate* isolate)
 {
 	v8::Handle global = v8::ObjectTemplate::New(isolate);
 	v8::Handle context = v8::Context::New(isolate, NULL, global);
-	if (context.IsEmpty())
-	{
-		// TODO: throw an exception
-	}
 	return context;
 }
 
@@ -135,20 +141,13 @@ JSV8Env JSV8Engine::s_env = JSV8Env();
 const char* JSV8Value::asCString() const
 {
 	if (m_value.IsEmpty())
-	{
-		// TODO: handle exceptions
 		return "";
-	}
 
 	else if (m_value->IsUndefined())
 		return "undefined";
-//	else if (m_value->IsNativeError())
-//	{
-//		v8::String::Utf8Value str(m_value);
-//		return *str ? *str : "error";
-//	}
+
 	v8::String::Utf8Value str(m_value);
-	return *str ? *str : "";
+	return toCString(str);
 }
 
 JSV8Env::JSV8Env()
@@ -198,9 +197,9 @@ JSV8Value JSV8Engine::eval(const char* _cstr) const
 	v8::Local name(v8::String::NewFromUtf8(context()->GetIsolate(), "(shell)"));
 	v8::ScriptOrigin origin(name);
 	v8::Handle script = v8::Script::Compile(source, &origin);
+
 	// Make sure to wrap the exception in a new handle because
 	// the handle returned from the TryCatch is destroyed
-	// TODO: improve this cause sometimes incorrect message is being sent!
 	if (script.IsEmpty())
 	{
 		reportException(context()->GetIsolate(), &tryCatch);
diff --git a/libjsengine/JSV8RPC.cpp b/libjsengine/JSV8RPC.cpp
index 688bdb50f..fa18bd35d 100644
--- a/libjsengine/JSV8RPC.cpp
+++ b/libjsengine/JSV8RPC.cpp
@@ -49,7 +49,7 @@ void JSV8RPCSend(v8::FunctionCallbackInfo const& args)
 	v8::String::Utf8Value str(stringifiedArg);
 	that->onSend(*str);
 
-	v8::Local values[1] = {v8::String::NewFromUtf8(args.GetIsolate(), that->m_lastResponse)};
+	v8::Local values[1] = {v8::String::NewFromUtf8(args.GetIsolate(), that->lastResponse())};
 	args.GetReturnValue().Set(parseFunc->Call(parseFunc, 1, values));
 }
 
diff --git a/libjsengine/JSV8RPC.h b/libjsengine/JSV8RPC.h
index a9bef8530..7dfb42392 100644
--- a/libjsengine/JSV8RPC.h
+++ b/libjsengine/JSV8RPC.h
@@ -33,12 +33,14 @@ class JSV8RPC
 {
 public:
 	JSV8RPC(JSV8Engine const& _engine);
-
 	virtual void onSend(const char* _payload) = 0;
-	const char* m_lastResponse;
+	const char* lastResponse() const { return m_lastResponse; }
 
 private:
 	JSV8Engine const& m_engine;
+
+protected:
+	const char* m_lastResponse;
 };
 
 }

From e5467878901dcdcc9a13a368d89eb7e4a3779ec5 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Mon, 4 May 2015 23:34:47 +0200
Subject: [PATCH 24/87] downgrade v8 to 3.15

---
 cmake/EthDependencies.cmake |   3 +-
 cmake/Findv8.cmake          |  20 +----
 libjsengine/JSV8Engine.cpp  | 174 ++++++++++++++++++------------------
 libjsengine/JSV8Engine.h    |   1 -
 libjsengine/JSV8Printer.cpp |   8 +-
 libjsengine/JSV8RPC.cpp     |  34 ++++---
 6 files changed, 111 insertions(+), 129 deletions(-)

diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake
index 01564632f..1e4651d3d 100644
--- a/cmake/EthDependencies.cmake
+++ b/cmake/EthDependencies.cmake
@@ -31,7 +31,8 @@ endif()
 
 # homebrew installs qts in opt
 if (APPLE)
-	set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/qt5")
+	set (CMAKE_PREFIX_PATH "/usr/local/opt/qt5" ${CMAKE_PREFIX_PATH})
+	set (CMAKE_PREFIX_PATH "/usr/local/opt/v8-315" ${CMAKE_PREFIX_PATH})
 endif()
 
 find_program(CTEST_COMMAND ctest)
diff --git a/cmake/Findv8.cmake b/cmake/Findv8.cmake
index 49c797586..cc1cab8a3 100644
--- a/cmake/Findv8.cmake
+++ b/cmake/Findv8.cmake
@@ -25,25 +25,11 @@ find_library(
 find_library(
 	V8_BASE_LIBRARY
 	NAMES v8_base
-	DOC "v8 library"
-)
-
-find_library(
-	V8_LIBBASE_LIBRARY
-	NAMES v8_libbase
-	DOC "v8 library"
+	DOC "v8 base library"
 )
 
-find_library(
-	V8_LIBPLATFORM_LIBRARY
-	NAMES v8_libplatform
-	DOC "v8 library"
-)
-
-string(REPLACE "/include" "" V8_INCLUDE_DIR_LOCATION ${V8_INCLUDE_DIR})
-
-set(V8_INCLUDE_DIRS ${V8_INCLUDE_DIR} ${V8_INCLUDE_DIR_LOCATION})
-set(V8_LIBRARIES ${V8_LIBRARY} ${V8_BASE_LIBRARY} ${V8_LIBBASE_LIBRARY} ${V8_LIBPLATFORM_LIBRARY})
+set(V8_INCLUDE_DIRS ${V8_INCLUDE_DIR})
+set(V8_LIBRARIES ${V8_LIBRARY} ${V8_BASE_LIBRARY})
 
 # debug library on windows
 # same naming convention as in qt (appending debug library with d)
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index a19199dce..8e35a7e0d 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -21,7 +21,7 @@
  */
 
 #include 
-#include 
+//#include 
 #include "JSV8Engine.h"
 #include "libjsengine/JSEngineResources.hpp"
 
@@ -42,59 +42,59 @@ static const char* toCString(v8::String::Utf8Value const& value)
 // from https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
 static void reportException(v8::Isolate* isolate, v8::TryCatch* try_catch)
 {
-	v8::HandleScope handle_scope(isolate);
-	v8::String::Utf8Value exception(try_catch->Exception());
-	const char* exception_string = toCString(exception);
-	v8::Handle message = try_catch->Message();
-
-	// V8 didn't provide any extra information about this error; just
-	// print the exception.
-	if (message.IsEmpty())
-		fprintf(stderr, "%s\n", exception_string);
-	else
-	{
-		// Print (filename):(line number): (message).
-		v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
-		const char* filename_string = toCString(filename);
-		int linenum = message->GetLineNumber();
-		fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
-
-		// Print line of source code.
-		v8::String::Utf8Value sourceline(message->GetSourceLine());
-		const char* sourceline_string = toCString(sourceline);
-		fprintf(stderr, "%s\n", sourceline_string);
-
-		// Print wavy underline (GetUnderline is deprecated).
-		int start = message->GetStartColumn();
-
-		for (int i = 0; i < start; i++)
-			fprintf(stderr, " ");
-
-		int end = message->GetEndColumn();
-
-		for (int i = start; i < end; i++)
-			fprintf(stderr, "^");
-
-		fprintf(stderr, "\n");
-		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
-
-		if (stack_trace.length() > 0)
-		{
-			const char* stack_trace_string = toCString(stack_trace);
-			fprintf(stderr, "%s\n", stack_trace_string);
-		}
-	}
+//	v8::HandleScope handle_scope;
+//	v8::String::Utf8Value exception(try_catch->Exception());
+//	const char* exception_string = toCString(exception);
+//	v8::Handle message = try_catch->Message();
+//
+//	 V8 didn't provide any extra information about this error; just
+//	 print the exception.
+//	if (message.IsEmpty())
+//		fprintf(stderr, "%s\n", exception_string);
+//	else
+//	{
+//		 Print (filename):(line number): (message).
+//		v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
+//		const char* filename_string = toCString(filename);
+//		int linenum = message->GetLineNumber();
+//		fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
+//
+//		 Print line of source code.
+//		v8::String::Utf8Value sourceline(message->GetSourceLine());
+//		const char* sourceline_string = toCString(sourceline);
+//		fprintf(stderr, "%s\n", sourceline_string);
+//
+//		 Print wavy underline (GetUnderline is deprecated).
+//		int start = message->GetStartColumn();
+//
+//		for (int i = 0; i < start; i++)
+//			fprintf(stderr, " ");
+//
+//		int end = message->GetEndColumn();
+//
+//		for (int i = start; i < end; i++)
+//			fprintf(stderr, "^");
+//
+//		fprintf(stderr, "\n");
+//		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
+//
+//		if (stack_trace.length() > 0)
+//		{
+//			const char* stack_trace_string = toCString(stack_trace);
+//			fprintf(stderr, "%s\n", stack_trace_string);
+//		}
+//	}
 }
 
-class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
-public:
-	virtual void* Allocate(size_t length) {
-		void* data = AllocateUninitialized(length);
-		return data == NULL ? data : memset(data, 0, length);
-	}
-	virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
-	virtual void Free(void* data, size_t) { free(data); }
-};
+//class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+//public:
+//	virtual void* Allocate(size_t length) {
+//		void* data = AllocateUninitialized(length);
+//		return data == NULL ? data : memset(data, 0, length);
+//	}
+//	virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
+//	virtual void Free(void* data, size_t) { free(data); }
+//};
 
 class JSV8Env
 {
@@ -104,32 +104,37 @@ public:
 	~JSV8Env();
 
 private:
-	v8::Platform *m_platform;
+//	v8::Platform *m_platform;
 };
 
-v8::Handle createShellContext(v8::Isolate* isolate)
+v8::Handle createShellContext()
 {
-	v8::Handle global = v8::ObjectTemplate::New(isolate);
-	v8::Handle context = v8::Context::New(isolate, NULL, global);
-	return context;
+	v8::Handle global = v8::ObjectTemplate::New();
+	return v8::Context::New(NULL, global);
 }
 
 class JSV8Scope
 {
 public:
-	JSV8Scope(v8::Isolate* _isolate):
-			m_isolateScope(_isolate),
-			m_handleScope(_isolate),
-			m_context(createShellContext(_isolate)),
+	JSV8Scope():
+			m_handleScope(),
+			m_context(createShellContext()),
 			m_contextScope(m_context)
-	{}
+	{
+		m_context->Enter();
+	}
+
+	~JSV8Scope()
+	{
+		m_context->Exit();
+		m_context.Dispose();
+	}
 
-	v8::Handle  const& context() const { return m_context; }
+	v8::Persistent  const& context() const { return m_context; }
 
 private:
-	v8::Isolate::Scope m_isolateScope;
 	v8::HandleScope m_handleScope;
-	v8::Handle  m_context;
+	v8::Persistent  m_context;
 	v8::Context::Scope m_contextScope;
 };
 
@@ -152,28 +157,22 @@ const char* JSV8Value::asCString() const
 
 JSV8Env::JSV8Env()
 {
-	static bool initialized = false;
-	if (initialized)
-		return;
-	initialized = true;
-	v8::V8::InitializeICU();
-	m_platform = v8::platform::CreateDefaultPlatform();
-	v8::V8::InitializePlatform(m_platform);
-	v8::V8::Initialize();
-	ShellArrayBufferAllocator array_buffer_allocator;
-	v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
+//	v8::V8::InitializeICU();
+//	m_platform = v8::platform::CreateDefaultPlatform();
+//	v8::V8::InitializePlatform(m_platform);
+//	v8::V8::Initialize();
+//	ShellArrayBufferAllocator array_buffer_allocator;
+//	v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
 }
 
 JSV8Env::~JSV8Env()
 {
 	v8::V8::Dispose();
-	v8::V8::ShutdownPlatform();
-	delete m_platform;
+//	v8::V8::ShutdownPlatform();
+//	delete m_platform;
 }
 
-JSV8Engine::JSV8Engine():
-		m_isolate(v8::Isolate::New()),
-		m_scope(new JSV8Scope(m_isolate))
+JSV8Engine::JSV8Engine(): m_scope(new JSV8Scope())
 {
 	JSEngineResources resources;
 	string common = resources.loadResourceAsString("common");
@@ -186,15 +185,14 @@ JSV8Engine::JSV8Engine():
 JSV8Engine::~JSV8Engine()
 {
 	delete m_scope;
-	m_isolate->Dispose();
 }
 
 JSV8Value JSV8Engine::eval(const char* _cstr) const
 {
-	v8::HandleScope handleScope(m_isolate);
+	v8::HandleScope handleScope;
 	v8::TryCatch tryCatch;
-	v8::Local source = v8::String::NewFromUtf8(context()->GetIsolate(), _cstr);
-	v8::Local name(v8::String::NewFromUtf8(context()->GetIsolate(), "(shell)"));
+	v8::Local source = v8::String::New(_cstr);
+	v8::Local name(v8::String::New("(shell)"));
 	v8::ScriptOrigin origin(name);
 	v8::Handle script = v8::Script::Compile(source, &origin);
 
@@ -202,16 +200,16 @@ JSV8Value JSV8Engine::eval(const char* _cstr) const
 	// the handle returned from the TryCatch is destroyed
 	if (script.IsEmpty())
 	{
-		reportException(context()->GetIsolate(), &tryCatch);
-		return v8::Exception::Error(v8::Local::New(context()->GetIsolate(), tryCatch.Message()->Get()));
+//		reportException(&tryCatch);
+		return v8::Exception::Error(v8::Local::New(tryCatch.Message()->Get()));
 	}
 
 	auto result = script->Run();
 
 	if (result.IsEmpty())
 	{
-		reportException(context()->GetIsolate(), &tryCatch);
-		return v8::Exception::Error(v8::Local::New(context()->GetIsolate(), tryCatch.Message()->Get()));
+//		reportException(&tryCatch);
+		return v8::Exception::Error(v8::Local::New(tryCatch.Message()->Get()));
 	}
 
 	return result;
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
index 7af72a8fe..0ec982b8b 100644
--- a/libjsengine/JSV8Engine.h
+++ b/libjsengine/JSV8Engine.h
@@ -54,7 +54,6 @@ public:
 
 private:
 	static JSV8Env s_env;
-	v8::Isolate* m_isolate;
 	JSV8Scope* m_scope;
 };
 
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index 0c7cbb3e0..622c8d7dc 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -37,11 +37,11 @@ JSV8Printer::JSV8Printer(JSV8Engine const& _engine): m_engine(_engine)
 
 const char* JSV8Printer::prettyPrint(JSV8Value const& _value) const
 {
-	v8::HandleScope handleScope(m_engine.context()->GetIsolate());
-	v8::Local pp = v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "prettyPrint");
+	v8::HandleScope handleScope;
+	v8::Local pp = v8::String::New("prettyPrint");
 	v8::Handle func = v8::Handle::Cast(m_engine.context()->Global()->Get(pp));
-	v8::Local values[1] = {_value.value()};
-	v8::Local res = v8::Local::Cast(func->Call(func, 1, values));
+	v8::Local values[1] = {v8::Local::New(_value.value())};
+	v8::Local res = func->Call(func, 1, values);
 	v8::String::Utf8Value str(res);
 	return *str ? *str : "";
 }
diff --git a/libjsengine/JSV8RPC.cpp b/libjsengine/JSV8RPC.cpp
index fa18bd35d..e75bfeada 100644
--- a/libjsengine/JSV8RPC.cpp
+++ b/libjsengine/JSV8RPC.cpp
@@ -20,10 +20,8 @@
  * Ethereum client.
  */
 
-#include "libjsconsole/JSConsoleResources.hpp"
 #include "JSV8RPC.h"
 
-using namespace std;
 using namespace dev;
 using namespace dev::eth;
 
@@ -32,12 +30,12 @@ namespace dev
 namespace eth
 {
 
-void JSV8RPCSend(v8::FunctionCallbackInfo const& args)
+v8::Handle JSV8RPCSend(v8::Arguments const& args)
 {
-	v8::Local JSON = v8::String::NewFromUtf8(args.GetIsolate(), "JSON");
-	v8::Local parse = v8::String::NewFromUtf8(args.GetIsolate(), "parse");
-	v8::Local stringify = v8::String::NewFromUtf8(args.GetIsolate(), "stringify");
-	v8::Handle jsonObject = v8::Handle::Cast(args.GetIsolate()->GetCurrentContext()->Global()->Get(JSON));
+	v8::Local JSON = v8::String::New("JSON");
+	v8::Local parse = v8::String::New("parse");
+	v8::Local stringify = v8::String::New("stringify");
+	v8::Handle jsonObject = v8::Handle::Cast(v8::Context::GetCurrent()->Global()->Get(JSON));
 	v8::Handle parseFunc = v8::Handle::Cast(jsonObject->Get(parse));
 	v8::Handle stringifyFunc = v8::Handle::Cast(jsonObject->Get(stringify));
 
@@ -49,8 +47,8 @@ void JSV8RPCSend(v8::FunctionCallbackInfo const& args)
 	v8::String::Utf8Value str(stringifiedArg);
 	that->onSend(*str);
 
-	v8::Local values[1] = {v8::String::NewFromUtf8(args.GetIsolate(), that->lastResponse())};
-	args.GetReturnValue().Set(parseFunc->Call(parseFunc, 1, values));
+	v8::Local values[1] = {v8::String::New(that->lastResponse())};
+	return parseFunc->Call(parseFunc, 1, values);
 }
 
 }
@@ -58,19 +56,19 @@ void JSV8RPCSend(v8::FunctionCallbackInfo const& args)
 
 JSV8RPC::JSV8RPC(JSV8Engine const &_engine): m_engine(_engine)
 {
-	v8::HandleScope scope(m_engine.context()->GetIsolate());
-	v8::Local rpcTemplate = v8::ObjectTemplate::New(m_engine.context()->GetIsolate());
+	v8::HandleScope scope;
+	v8::Local rpcTemplate = v8::ObjectTemplate::New();
 	rpcTemplate->SetInternalFieldCount(1);
-	rpcTemplate->Set(v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "send"),
-	                 v8::FunctionTemplate::New(m_engine.context()->GetIsolate(), JSV8RPCSend));
-	rpcTemplate->Set(v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "sendAsync"),
-	                 v8::FunctionTemplate::New(m_engine.context()->GetIsolate(), JSV8RPCSend));
+	rpcTemplate->Set(v8::String::New("send"),
+	                 v8::FunctionTemplate::New(JSV8RPCSend));
+	rpcTemplate->Set(v8::String::New("sendAsync"),
+	                 v8::FunctionTemplate::New(JSV8RPCSend));
 
 	v8::Local obj = rpcTemplate->NewInstance();
-	obj->SetInternalField(0, v8::External::New(m_engine.context()->GetIsolate(), this));
+	obj->SetInternalField(0, v8::External::New(this));
 
-	v8::Local web3 = v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "web3");
-	v8::Local setProvider = v8::String::NewFromUtf8(m_engine.context()->GetIsolate(), "setProvider");
+	v8::Local web3 = v8::String::New("web3");
+	v8::Local setProvider = v8::String::New("setProvider");
 	v8::Handle web3object = v8::Handle::Cast(m_engine.context()->Global()->Get(web3));
 	v8::Handle func = v8::Handle::Cast(web3object->Get(setProvider));
 	v8::Local values[1] = {obj};

From 3c38241b0cec2762714d4010a37ede207c77dc4b Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Mon, 4 May 2015 23:48:00 +0200
Subject: [PATCH 25/87] little cleanup after downgrade

---
 libjsconsole/CMakeLists.txt |   2 +-
 libjsengine/CMakeLists.txt  |   2 +-
 libjsengine/JSV8Engine.cpp  | 129 ++++++++++++++----------------------
 3 files changed, 52 insertions(+), 81 deletions(-)

diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt
index 932cd20dd..f54b7a1c7 100644
--- a/libjsconsole/CMakeLists.txt
+++ b/libjsconsole/CMakeLists.txt
@@ -10,8 +10,8 @@ set(CMAKE_AUTOMOC OFF)
 
 aux_source_directory(. SRC_LIST)
 
+include_directories(BEFORE ${V8_INCLUDE_DIRS})
 include_directories(BEFORE ..)
-include_directories(${V8_INCLUDE_DIRS})
 include_directories(${READLINE_INCLUDE_DIRS})
 include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
 
diff --git a/libjsengine/CMakeLists.txt b/libjsengine/CMakeLists.txt
index d16d1b102..0023494c6 100644
--- a/libjsengine/CMakeLists.txt
+++ b/libjsengine/CMakeLists.txt
@@ -10,8 +10,8 @@ set(CMAKE_AUTOMOC OFF)
 
 aux_source_directory(. SRC_LIST)
 
+include_directories(BEFORE ${V8_INCLUDE_DIRS})
 include_directories(BEFORE ..)
-include_directories(${V8_INCLUDE_DIRS})
 
 set(EXECUTABLE jsengine)
 
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 8e35a7e0d..8af2386ec 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -39,72 +39,60 @@ static const char* toCString(v8::String::Utf8Value const& value)
 	return *value ? *value : "";
 }
 
-// from https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
-static void reportException(v8::Isolate* isolate, v8::TryCatch* try_catch)
+// from:        https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
+// v3.15 from:  https://chromium.googlesource.com/v8/v8.git/+/3.14.5.9/samples/shell.cc
+void reportException(v8::TryCatch* try_catch)
 {
-//	v8::HandleScope handle_scope;
-//	v8::String::Utf8Value exception(try_catch->Exception());
-//	const char* exception_string = toCString(exception);
-//	v8::Handle message = try_catch->Message();
-//
-//	 V8 didn't provide any extra information about this error; just
-//	 print the exception.
-//	if (message.IsEmpty())
-//		fprintf(stderr, "%s\n", exception_string);
-//	else
-//	{
-//		 Print (filename):(line number): (message).
-//		v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
-//		const char* filename_string = toCString(filename);
-//		int linenum = message->GetLineNumber();
-//		fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
-//
-//		 Print line of source code.
-//		v8::String::Utf8Value sourceline(message->GetSourceLine());
-//		const char* sourceline_string = toCString(sourceline);
-//		fprintf(stderr, "%s\n", sourceline_string);
-//
-//		 Print wavy underline (GetUnderline is deprecated).
-//		int start = message->GetStartColumn();
-//
-//		for (int i = 0; i < start; i++)
-//			fprintf(stderr, " ");
-//
-//		int end = message->GetEndColumn();
-//
-//		for (int i = start; i < end; i++)
-//			fprintf(stderr, "^");
-//
-//		fprintf(stderr, "\n");
-//		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
-//
-//		if (stack_trace.length() > 0)
-//		{
-//			const char* stack_trace_string = toCString(stack_trace);
-//			fprintf(stderr, "%s\n", stack_trace_string);
-//		}
-//	}
+	v8::HandleScope handle_scope;
+	v8::String::Utf8Value exception(try_catch->Exception());
+	const char* exception_string = toCString(exception);
+	v8::Handle message = try_catch->Message();
+
+	// V8 didn't provide any extra information about this error; just
+	// print the exception.
+	if (message.IsEmpty())
+		printf("%s\n", exception_string);
+	else
+	{
+		// Print (filename):(line number): (message).
+		v8::String::Utf8Value filename(message->GetScriptResourceName());
+		const char* filename_string = toCString(filename);
+		int linenum = message->GetLineNumber();
+		printf("%s:%i: %s\n", filename_string, linenum, exception_string);
+
+		// Print line of source code.
+		v8::String::Utf8Value sourceline(message->GetSourceLine());
+		const char* sourceline_string = toCString(sourceline);
+		printf("%s\n", sourceline_string);
+
+		// Print wavy underline (GetUnderline is deprecated).
+		int start = message->GetStartColumn();
+		for (int i = 0; i < start; i++)
+			printf(" ");
+
+		int end = message->GetEndColumn();
+
+		for (int i = start; i < end; i++)
+			printf("^");
+
+		printf("\n");
+
+		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
+		if (stack_trace.length() > 0)
+		{
+			const char* stack_trace_string = toCString(stack_trace);
+			printf("%s\n", stack_trace_string);
+		}
+	}
 }
 
-//class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
-//public:
-//	virtual void* Allocate(size_t length) {
-//		void* data = AllocateUninitialized(length);
-//		return data == NULL ? data : memset(data, 0, length);
-//	}
-//	virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
-//	virtual void Free(void* data, size_t) { free(data); }
-//};
-
 class JSV8Env
 {
 public:
-	JSV8Env();
-
-	~JSV8Env();
-
-private:
-//	v8::Platform *m_platform;
+	~JSV8Env()
+	{
+		v8::V8::Dispose();
+	}
 };
 
 v8::Handle createShellContext()
@@ -155,23 +143,6 @@ const char* JSV8Value::asCString() const
 	return toCString(str);
 }
 
-JSV8Env::JSV8Env()
-{
-//	v8::V8::InitializeICU();
-//	m_platform = v8::platform::CreateDefaultPlatform();
-//	v8::V8::InitializePlatform(m_platform);
-//	v8::V8::Initialize();
-//	ShellArrayBufferAllocator array_buffer_allocator;
-//	v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
-}
-
-JSV8Env::~JSV8Env()
-{
-	v8::V8::Dispose();
-//	v8::V8::ShutdownPlatform();
-//	delete m_platform;
-}
-
 JSV8Engine::JSV8Engine(): m_scope(new JSV8Scope())
 {
 	JSEngineResources resources;
@@ -200,7 +171,7 @@ JSV8Value JSV8Engine::eval(const char* _cstr) const
 	// the handle returned from the TryCatch is destroyed
 	if (script.IsEmpty())
 	{
-//		reportException(&tryCatch);
+		reportException(&tryCatch);
 		return v8::Exception::Error(v8::Local::New(tryCatch.Message()->Get()));
 	}
 
@@ -208,7 +179,7 @@ JSV8Value JSV8Engine::eval(const char* _cstr) const
 
 	if (result.IsEmpty())
 	{
-//		reportException(&tryCatch);
+		reportException(&tryCatch);
 		return v8::Exception::Error(v8::Local::New(tryCatch.Message()->Get()));
 	}
 

From 70512e7d763720d5fb2ce5c86001827606d24ac9 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Tue, 5 May 2015 00:20:07 +0200
Subject: [PATCH 26/87] fixes for linux

---
 cmake/Findv8.cmake         | 8 +-------
 libjsconsole/JSConsole.cpp | 3 ++-
 2 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/cmake/Findv8.cmake b/cmake/Findv8.cmake
index cc1cab8a3..2451c708f 100644
--- a/cmake/Findv8.cmake
+++ b/cmake/Findv8.cmake
@@ -22,14 +22,8 @@ find_library(
 	DOC "v8 library"
 )
 
-find_library(
-	V8_BASE_LIBRARY
-	NAMES v8_base
-	DOC "v8 base library"
-)
-
 set(V8_INCLUDE_DIRS ${V8_INCLUDE_DIR})
-set(V8_LIBRARIES ${V8_LIBRARY} ${V8_BASE_LIBRARY})
+set(V8_LIBRARIES ${V8_LIBRARY})
 
 # debug library on windows
 # same naming convention as in qt (appending debug library with d)
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index 284fba4e3..c59c1e198 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -26,8 +26,9 @@
 #include "JSV8Connector.h"
 #include "libjsconsole/JSConsoleResources.hpp"
 
-// TODO: readline!
+// TODO! make readline optional!
 #include 
+#include 
 
 using namespace std;
 using namespace dev;

From 07fb87681cd54113f3082c136cf66beb0981e639 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Tue, 5 May 2015 08:29:46 +0200
Subject: [PATCH 27/87] cleanup

---
 cmake/EthUtils.cmake       | 2 +-
 libdevcore/CommonIO.cpp    | 2 +-
 libjsengine/JSV8Engine.cpp | 1 -
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/cmake/EthUtils.cmake b/cmake/EthUtils.cmake
index aed74a4bb..a426b1218 100644
--- a/cmake/EthUtils.cmake
+++ b/cmake/EthUtils.cmake
@@ -74,7 +74,7 @@ function(eth_add_resources RESOURCE_FILE OUT_FILE)
 		list(APPEND filenames "${${resource}}")
 	endforeach(resource)
 
-    add_custom_command(OUTPUT ${OUTPUT}
+	add_custom_command(OUTPUT ${OUTPUT}
 		COMMAND ${CMAKE_COMMAND} -DETH_RES_FILE="${RESOURCE_FILE}" -P "${ETH_SCRIPTS_DIR}/resources.cmake"
 		DEPENDS ${filenames}
 	)
diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp
index 5b90a9079..a1a1056cb 100644
--- a/libdevcore/CommonIO.cpp
+++ b/libdevcore/CommonIO.cpp
@@ -30,7 +30,7 @@ string dev::memDump(bytes const& _bytes, unsigned _width, bool _html)
 {
 	stringstream ret;
 	if (_html)
-		ret << "
";
+		ret << "
";
 	for (unsigned i = 0; i < _bytes.size(); i += _width)
 	{
 		ret << hex << setw(4) << setfill('0') << i << " ";
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 8af2386ec..26e4479e8 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -21,7 +21,6 @@
  */
 
 #include 
-//#include 
 #include "JSV8Engine.h"
 #include "libjsengine/JSEngineResources.hpp"
 

From 5c2be28a2d2b009327c108a97b89b8e6e7c046c8 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Tue, 5 May 2015 10:37:14 +0200
Subject: [PATCH 28/87] wrap const char* in jsstring

---
 eth/main.cpp                    |  4 ----
 libjsconsole/JSConsole.cpp      |  2 +-
 libjsengine/JSEngine.cpp        | 13 +++++++++++++
 libjsengine/JSEngine.h          | 12 +++++++++++-
 libjsengine/JSPrinter.h         |  6 ++++--
 libjsengine/JSV8Engine.cpp      |  2 +-
 libjsengine/JSV8Engine.h        |  2 +-
 libjsengine/JSV8Printer.cpp     |  2 +-
 libjsengine/JSV8Printer.h       |  2 +-
 test/libjsengine/JSV8Engine.cpp | 14 +++++++-------
 10 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/eth/main.cpp b/eth/main.cpp
index f1b2c0358..bd8f7d516 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -1645,12 +1645,8 @@ int main(int argc, char** argv)
 			}
 	}
 	else
-	{
 		while (!g_exit)
-		{
 			this_thread::sleep_for(chrono::milliseconds(1000));
-		}
-	}
 
 	StructuredLogger::stopping(clientImplString, dev::Version);
 	auto netData = web3.saveNetwork();
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index c59c1e198..e084f010f 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -69,7 +69,7 @@ void JSConsole::repl() const
 	{
 		add_history(cmd.c_str());
 		auto value = m_engine.eval(cmd.c_str());
-		string result = m_printer.prettyPrint(value);
+		string result = m_printer.prettyPrint(value).cstr();
 		cout << result << endl;
 	}
 }
diff --git a/libjsengine/JSEngine.cpp b/libjsengine/JSEngine.cpp
index 47afbd34e..f4a5a54c1 100644
--- a/libjsengine/JSEngine.cpp
+++ b/libjsengine/JSEngine.cpp
@@ -20,4 +20,17 @@
  * Ethereum client.
  */
 
+#include 
+#include 
 #include "JSEngine.h"
+
+using namespace dev;
+using namespace dev::eth;
+
+JSString::JSString(char const *_cstr): m_cstr(strdup(_cstr)) {}
+
+JSString::~JSString()
+{
+	if (m_cstr)
+		free(m_cstr);
+}
diff --git a/libjsengine/JSEngine.h b/libjsengine/JSEngine.h
index 7df55c2f5..275ffd2ec 100644
--- a/libjsengine/JSEngine.h
+++ b/libjsengine/JSEngine.h
@@ -27,10 +27,20 @@ namespace dev
 namespace eth
 {
 
+class JSString
+{
+public:
+	JSString(char const* _cstr);
+	~JSString();
+	char const* cstr() const { return m_cstr; }
+private:
+	char* m_cstr;
+};
+
 class JSValue
 {
 public:
-	virtual const char* asCString() const = 0;
+	virtual JSString toString() const = 0;
 };
 
 template 
diff --git a/libjsengine/JSPrinter.h b/libjsengine/JSPrinter.h
index 173ac2c87..d5f84d2d3 100644
--- a/libjsengine/JSPrinter.h
+++ b/libjsengine/JSPrinter.h
@@ -22,6 +22,8 @@
 
 #pragma once
 
+#include "JSEngine.h"
+
 namespace dev
 {
 namespace eth
@@ -31,8 +33,8 @@ template 
 class JSPrinter
 {
 public:
-	virtual const char* print(T const& _value) const { return _value.asCString(); }
-	virtual const char* prettyPrint(T const& _value) const { return print(_value); }
+	virtual JSString print(T const& _value) const { return _value.toString(); }
+	virtual JSString prettyPrint(T const& _value) const { return print(_value); }
 };
 
 }
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 26e4479e8..78710c037 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -130,7 +130,7 @@ private:
 
 JSV8Env JSV8Engine::s_env = JSV8Env();
 
-const char* JSV8Value::asCString() const
+JSString JSV8Value::toString() const
 {
 	if (m_value.IsEmpty())
 		return "";
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
index 0ec982b8b..085d8ffbe 100644
--- a/libjsengine/JSV8Engine.h
+++ b/libjsengine/JSV8Engine.h
@@ -37,7 +37,7 @@ class JSV8Value : public JSValue
 {
 public:
 	JSV8Value(v8::Handle _value): m_value(_value) {}
-	const char* asCString() const;
+	JSString toString() const;
 
 	v8::Handle const& value() const { return m_value; }
 private:
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index 622c8d7dc..d76fdb95c 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -35,7 +35,7 @@ JSV8Printer::JSV8Printer(JSV8Engine const& _engine): m_engine(_engine)
 	m_engine.eval(prettyPrint.c_str());
 }
 
-const char* JSV8Printer::prettyPrint(JSV8Value const& _value) const
+JSString JSV8Printer::prettyPrint(JSV8Value const& _value) const
 {
 	v8::HandleScope handleScope;
 	v8::Local pp = v8::String::New("prettyPrint");
diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h
index b02b025f8..0d9d06e0d 100644
--- a/libjsengine/JSV8Printer.h
+++ b/libjsengine/JSV8Printer.h
@@ -34,7 +34,7 @@ class JSV8Printer : public JSPrinter
 {
 public:
 	JSV8Printer(JSV8Engine const& _engine);
-	const char* prettyPrint(JSV8Value const& _value) const;
+	JSString prettyPrint(JSV8Value const& _value) const;
 private:
 	JSV8Engine const& m_engine;
 };
diff --git a/test/libjsengine/JSV8Engine.cpp b/test/libjsengine/JSV8Engine.cpp
index 2f319ab71..da6a0da0e 100644
--- a/test/libjsengine/JSV8Engine.cpp
+++ b/test/libjsengine/JSV8Engine.cpp
@@ -17,7 +17,7 @@ BOOST_AUTO_TEST_CASE(evalInteger)
 	JSV8Engine engine;
 	JSV8Printer printer(engine);
 	auto value = engine.eval("1 + 1");
-	string result = printer.print(value);
+	string result = printer.print(value).cstr();
 	BOOST_CHECK_EQUAL(result, "2");
 }
 
@@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(evalString)
 	JSV8Engine engine;
 	JSV8Printer printer(engine);
 	auto value = engine.eval("'hello ' + 'world'");
-	string result = printer.print(value);
+	string result = printer.print(value).cstr();
 	BOOST_CHECK_EQUAL(result, "hello world");
 }
 
@@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(evalEmpty)
 	JSV8Engine engine;
 	JSV8Printer printer(engine);
 	auto value = engine.eval("");
-	string result = printer.print(value);
+	string result = printer.print(value).cstr();
 	BOOST_CHECK_EQUAL(result, "undefined");
 }
 
@@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(evalAssignment)
 	JSV8Engine engine;
 	JSV8Printer printer(engine);
 	auto value = engine.eval("x = 5");
-	string result = printer.print(value);
+	string result = printer.print(value).cstr();
 	BOOST_CHECK_EQUAL(result, "5");
 }
 
@@ -53,7 +53,7 @@ BOOST_AUTO_TEST_CASE(evalIncorrectExpression)
 	JSV8Engine engine;
 	JSV8Printer printer(engine);
 	auto value = engine.eval("[");
-	string result = printer.print(value);
+	string result = printer.print(value).cstr();
 	BOOST_CHECK_EQUAL(result, "Error: Uncaught SyntaxError: Unexpected end of input");
 }
 
@@ -62,8 +62,8 @@ BOOST_AUTO_TEST_CASE(evalNull)
 	JSV8Engine engine;
 	JSV8Printer printer(engine);
 	auto value = engine.eval("null");
-	string result = printer.print(value);
-	string prettyResult = printer.prettyPrint(value);
+	string result = printer.print(value).cstr();
+	string prettyResult = printer.prettyPrint(value).cstr();
 	BOOST_CHECK_EQUAL(result, "null");
 	BOOST_CHECK_EQUAL(prettyResult.find("null") != std::string::npos, true);
 }

From f56868493f01f95fdb787595c54d736dbaac0d5e Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 6 May 2015 10:02:50 +0200
Subject: [PATCH 29/87] duplicate code in eth/main.cpp wrapped into function

---
 eth/main.cpp | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/eth/main.cpp b/eth/main.cpp
index 6ffc87331..f333ce2d6 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -411,6 +411,13 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
 	exit(0);
 }
 
+void stopMiningAfterXBlocks(eth::Client *_c, unsigned _start, unsigned _mining)
+{
+	if (_c->isMining() && _c->blockChain().details().number - _start == _mining)
+		_c->stopMining();
+	this_thread::sleep_for(chrono::milliseconds(100));
+}
+
 int main(int argc, char** argv)
 {
 	cout << "\x1b[30mEthBlack\x1b[0m" << endl;
@@ -1642,19 +1649,13 @@ int main(int argc, char** argv)
 			while (!g_exit)
 			{
 				console.repl();
-				if (c->isMining() && c->blockChain().details().number - n == mining)
-					c->stopMining();
-				this_thread::sleep_for(chrono::milliseconds(100));
+				stopMiningAfterXBlocks(c, n, mining);
 			}
 #endif
 		}
 		else
 			while (!g_exit)
-			{
-				if (c->isMining() && c->blockChain().details().number - n == mining)
-					c->stopMining();
-				this_thread::sleep_for(chrono::milliseconds(100));
-			}
+				stopMiningAfterXBlocks(c, n, mining);
 	}
 	else
 		while (!g_exit)

From 06c228e6c081e44384a3b2f58d8ba6969002580e Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 6 May 2015 10:11:50 +0200
Subject: [PATCH 30/87] forward declarations of unique_ptr

---
 libjsconsole/JSConsole.cpp | 5 +++--
 libjsconsole/JSConsole.h   | 5 ++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index e084f010f..15fbb1671 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -22,6 +22,7 @@
 
 #include 
 #include 
+#include 
 #include "JSConsole.h"
 #include "JSV8Connector.h"
 #include "libjsconsole/JSConsoleResources.hpp"
@@ -42,6 +43,8 @@ JSConsole::JSConsole(WebThreeDirect& _web3, std::vector const& _ac
 	m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts));
 }
 
+JSConsole::~JSConsole() {}
+
 void JSConsole::repl() const
 {
 	string cmd = "";
@@ -81,5 +84,3 @@ std::string JSConsole::promptForIndentionLevel(int _i) const
 
 	return string((_i + 1) * 2, ' ');
 }
-
-
diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h
index 895aa9130..3b65691f6 100644
--- a/libjsconsole/JSConsole.h
+++ b/libjsconsole/JSConsole.h
@@ -24,7 +24,9 @@
 
 #include 
 #include 
-#include 
+
+class WebThreeStubServer;
+namespace jsonrpc { class AbstractServerConnector; }
 
 namespace dev
 {
@@ -35,6 +37,7 @@ class JSConsole
 {
 public:
 	JSConsole(WebThreeDirect& _web3, std::vector const& _accounts);
+	~JSConsole();
 	void repl() const;
 
 private:

From 8eee07518f868494258f0bcc283ea5e02178c1a6 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 6 May 2015 10:18:36 +0200
Subject: [PATCH 31/87] fixed printing undefined

---
 libjsengine/PrettyPrint.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libjsengine/PrettyPrint.js b/libjsengine/PrettyPrint.js
index 167c36aa6..f617cf29c 100644
--- a/libjsengine/PrettyPrint.js
+++ b/libjsengine/PrettyPrint.js
@@ -19,6 +19,8 @@ var prettyPrint = (function () {
             str += "\033[31m" + "Error:\033[0m " + object.message;
         }  else if (object === null) {
             str += "\033[1m\033[30m" + "null";
+        } else if(typeof(object) === "undefined") {
+            str += "\033[1m\033[30m" + object;
         } else if (isBigNumber(object)) {
             str += "\033[32m'" + object.toString(10) + "'";
         } else if(typeof(object) === "object") {
@@ -40,8 +42,6 @@ var prettyPrint = (function () {
             str += indent.substr(2, indent.length) + "}";
         } else if(typeof(object) === "string") {
             str += "\033[32m'" + object + "'";
-        } else if(typeof(object) === "undefined") {
-            str += "\033[1m\033[30m" + object;
         } else if(typeof(object) === "number") {
             str += "\033[31m" + object;
         } else if(typeof(object) === "function") {

From 36b4b46f6640b935c2becf6c23a5ea4c0ba8087a Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 6 May 2015 10:27:49 +0200
Subject: [PATCH 32/87] removed redundant createShellContext function && fixed
 style of JSV8Engine files

---
 libjsengine/JSV8Engine.cpp | 30 ++++++++++++------------------
 libjsengine/JSV8Engine.h   |  2 +-
 2 files changed, 13 insertions(+), 19 deletions(-)

diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 78710c037..466e88543 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -33,19 +33,19 @@ namespace dev
 namespace eth
 {
 
-static const char* toCString(v8::String::Utf8Value const& value)
+static char const* toCString(v8::String::Utf8Value const& _value)
 {
-	return *value ? *value : "";
+	return *_value ? *_value : "";
 }
 
 // from:        https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
 // v3.15 from:  https://chromium.googlesource.com/v8/v8.git/+/3.14.5.9/samples/shell.cc
-void reportException(v8::TryCatch* try_catch)
+void reportException(v8::TryCatch*_try_catch)
 {
 	v8::HandleScope handle_scope;
-	v8::String::Utf8Value exception(try_catch->Exception());
-	const char* exception_string = toCString(exception);
-	v8::Handle message = try_catch->Message();
+	v8::String::Utf8Value exception(_try_catch->Exception());
+	char const* exception_string = toCString(exception);
+	v8::Handle message = _try_catch->Message();
 
 	// V8 didn't provide any extra information about this error; just
 	// print the exception.
@@ -55,13 +55,13 @@ void reportException(v8::TryCatch* try_catch)
 	{
 		// Print (filename):(line number): (message).
 		v8::String::Utf8Value filename(message->GetScriptResourceName());
-		const char* filename_string = toCString(filename);
+		char const* filename_string = toCString(filename);
 		int linenum = message->GetLineNumber();
 		printf("%s:%i: %s\n", filename_string, linenum, exception_string);
 
 		// Print line of source code.
 		v8::String::Utf8Value sourceline(message->GetSourceLine());
-		const char* sourceline_string = toCString(sourceline);
+		char const* sourceline_string = toCString(sourceline);
 		printf("%s\n", sourceline_string);
 
 		// Print wavy underline (GetUnderline is deprecated).
@@ -76,10 +76,10 @@ void reportException(v8::TryCatch* try_catch)
 
 		printf("\n");
 
-		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
+		v8::String::Utf8Value stack_trace(_try_catch->StackTrace());
 		if (stack_trace.length() > 0)
 		{
-			const char* stack_trace_string = toCString(stack_trace);
+			char const* stack_trace_string = toCString(stack_trace);
 			printf("%s\n", stack_trace_string);
 		}
 	}
@@ -94,18 +94,12 @@ public:
 	}
 };
 
-v8::Handle createShellContext()
-{
-	v8::Handle global = v8::ObjectTemplate::New();
-	return v8::Context::New(NULL, global);
-}
-
 class JSV8Scope
 {
 public:
 	JSV8Scope():
 			m_handleScope(),
-			m_context(createShellContext()),
+			m_context(v8::Context::New(NULL, v8::ObjectTemplate::New())),
 			m_contextScope(m_context)
 	{
 		m_context->Enter();
@@ -157,7 +151,7 @@ JSV8Engine::~JSV8Engine()
 	delete m_scope;
 }
 
-JSV8Value JSV8Engine::eval(const char* _cstr) const
+JSV8Value JSV8Engine::eval(char const* _cstr) const
 {
 	v8::HandleScope handleScope;
 	v8::TryCatch tryCatch;
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
index 085d8ffbe..d785a71ba 100644
--- a/libjsengine/JSV8Engine.h
+++ b/libjsengine/JSV8Engine.h
@@ -49,7 +49,7 @@ class JSV8Engine : public JSEngine
 public:
 	JSV8Engine();
 	virtual ~JSV8Engine();
-	JSV8Value eval(const char* _cstr) const;
+	JSV8Value eval(char const* _cstr) const;
 	v8::Handle const& context() const;
 
 private:

From 23782112b40dd9fa61f9621df85327f2036b393e Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 6 May 2015 10:29:26 +0200
Subject: [PATCH 33/87] fixed style of JSEngine files

---
 libjsengine/JSEngine.cpp | 2 +-
 libjsengine/JSEngine.h   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libjsengine/JSEngine.cpp b/libjsengine/JSEngine.cpp
index f4a5a54c1..b2bad4859 100644
--- a/libjsengine/JSEngine.cpp
+++ b/libjsengine/JSEngine.cpp
@@ -27,7 +27,7 @@
 using namespace dev;
 using namespace dev::eth;
 
-JSString::JSString(char const *_cstr): m_cstr(strdup(_cstr)) {}
+JSString::JSString(char const* _cstr): m_cstr(strdup(_cstr)) {}
 
 JSString::~JSString()
 {
diff --git a/libjsengine/JSEngine.h b/libjsengine/JSEngine.h
index 275ffd2ec..94cd0631d 100644
--- a/libjsengine/JSEngine.h
+++ b/libjsengine/JSEngine.h
@@ -48,7 +48,7 @@ class JSEngine
 {
 public:
 	// should be used to evalute javascript expression
-	virtual T eval(const char* _cstr) const = 0;
+	virtual T eval(char const* _cstr) const = 0;
 };
 
 }

From 708affdc389896ef31550c4f78ca5bc2addcdd4f Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 6 May 2015 10:32:17 +0200
Subject: [PATCH 34/87] fixed constructor indention in JSV8Engine.cpp

---
 libjsengine/JSV8Engine.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 466e88543..30b0aa3b8 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -98,9 +98,9 @@ class JSV8Scope
 {
 public:
 	JSV8Scope():
-			m_handleScope(),
-			m_context(v8::Context::New(NULL, v8::ObjectTemplate::New())),
-			m_contextScope(m_context)
+		m_handleScope(),
+		m_context(v8::Context::New(NULL, v8::ObjectTemplate::New())),
+		m_contextScope(m_context)
 	{
 		m_context->Enter();
 	}

From 553676bc9e871b777dc81a1222a3a45859ace66d Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 6 May 2015 10:52:12 +0200
Subject: [PATCH 35/87] throwing exception if we cannot print jsvalue

---
 libjsengine/JSEngine.h      | 4 ++++
 libjsengine/JSV8Engine.cpp  | 4 +++-
 libjsengine/JSV8Printer.cpp | 4 +++-
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/libjsengine/JSEngine.h b/libjsengine/JSEngine.h
index 94cd0631d..78937a536 100644
--- a/libjsengine/JSEngine.h
+++ b/libjsengine/JSEngine.h
@@ -21,12 +21,16 @@
  */
 
 #pragma once
+#include 
 
 namespace dev
 {
 namespace eth
 {
 
+class JSException: public std::exception {};
+class JSPrintException: public JSException { char const* what() const noexcept { return "Cannot print expression!"; } };
+
 class JSString
 {
 public:
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 30b0aa3b8..437bcb6a4 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -35,7 +35,9 @@ namespace eth
 
 static char const* toCString(v8::String::Utf8Value const& _value)
 {
-	return *_value ? *_value : "";
+	if (*_value)
+		return *_value;
+	throw JSPrintException();
 }
 
 // from:        https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
diff --git a/libjsengine/JSV8Printer.cpp b/libjsengine/JSV8Printer.cpp
index d76fdb95c..93c235859 100644
--- a/libjsengine/JSV8Printer.cpp
+++ b/libjsengine/JSV8Printer.cpp
@@ -43,5 +43,7 @@ JSString JSV8Printer::prettyPrint(JSV8Value const& _value) const
 	v8::Local values[1] = {v8::Local::New(_value.value())};
 	v8::Local res = func->Call(func, 1, values);
 	v8::String::Utf8Value str(res);
-	return *str ? *str : "";
+	if (*str)
+		return *str;
+	throw JSPrintException();
 }

From 30c832e3582f341c4fbddc90fd9a0e528349d423 Mon Sep 17 00:00:00 2001
From: chriseth 
Date: Wed, 29 Apr 2015 18:16:05 +0200
Subject: [PATCH 36/87] Split known state from common subexpression eliminator.

---
 libevmasm/Assembly.cpp                      |   3 +-
 libevmasm/CommonSubexpressionEliminator.cpp | 267 ++-----------------
 libevmasm/CommonSubexpressionEliminator.h   |  59 +----
 libevmasm/KnownState.cpp                    | 278 ++++++++++++++++++++
 libevmasm/KnownState.h                      | 149 +++++++++++
 test/libsolidity/SolidityOptimizer.cpp      |   6 +-
 6 files changed, 455 insertions(+), 307 deletions(-)
 create mode 100644 libevmasm/KnownState.cpp
 create mode 100644 libevmasm/KnownState.h

diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index 6cc09a4bc..c7253622e 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -329,7 +329,8 @@ Assembly& Assembly::optimise(bool _enable)
 		copt << "Performing common subexpression elimination...";
 		for (auto iter = m_items.begin(); iter != m_items.end();)
 		{
-			CommonSubexpressionEliminator eliminator;
+			KnownState state;
+			CommonSubexpressionEliminator eliminator(state);
 			auto orig = iter;
 			iter = eliminator.feedItems(iter, m_items.end());
 			AssemblyItems optItems;
diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp
index 63524d6f3..645a426d9 100644
--- a/libevmasm/CommonSubexpressionEliminator.cpp
+++ b/libevmasm/CommonSubexpressionEliminator.cpp
@@ -37,18 +37,19 @@ vector CommonSubexpressionEliminator::getOptimizedItems()
 
 	map initialStackContents;
 	map targetStackContents;
-	int minHeight = m_stackHeight + 1;
-	if (!m_stackElements.empty())
-		minHeight = min(minHeight, m_stackElements.begin()->first);
+	int minHeight = m_state.stackHeight() + 1;
+	if (!m_state.stackElements().empty())
+		minHeight = min(minHeight, m_state.stackElements().begin()->first);
 	for (int height = minHeight; height <= 0; ++height)
-		initialStackContents[height] = initialStackElement(height, SourceLocation());
-	for (int height = minHeight; height <= m_stackHeight; ++height)
-		targetStackContents[height] = stackElement(height, SourceLocation());
+		//@todo this is not nice as it is here - should be "unknownStackElement" - but is it really unknown?
+		initialStackContents[height] = m_state.initialStackElement(height, SourceLocation());
+	for (int height = minHeight; height <= m_state.stackHeight(); ++height)
+		targetStackContents[height] = m_state.stackElement(height, SourceLocation());
 
 	// Debug info:
 	//stream(cout, initialStackContents, targetStackContents);
 
-	AssemblyItems items = CSECodeGenerator(m_expressionClasses, m_storeOperations).generateCode(
+	AssemblyItems items = CSECodeGenerator(m_state.expressionClasses(), m_storeOperations).generateCode(
 		initialStackContents,
 		targetStackContents
 	);
@@ -57,103 +58,11 @@ vector CommonSubexpressionEliminator::getOptimizedItems()
 	return items;
 }
 
-ostream& CommonSubexpressionEliminator::stream(
-	ostream& _out,
-	map _initialStack,
-	map _targetStack
-) const
-{
-	auto streamExpressionClass = [this](ostream& _out, Id _id)
-	{
-		auto const& expr = m_expressionClasses.representative(_id);
-		_out << "  " << dec << _id << ": " << *expr.item;
-		if (expr.sequenceNumber)
-			_out << "@" << dec << expr.sequenceNumber;
-		_out << "(";
-		for (Id arg: expr.arguments)
-			_out << dec << arg << ",";
-		_out << ")" << endl;
-	};
-
-	_out << "Optimizer analysis:" << endl;
-	_out << "Final stack height: " << dec << m_stackHeight << endl;
-	_out << "Equivalence classes: " << endl;
-	for (Id eqClass = 0; eqClass < m_expressionClasses.size(); ++eqClass)
-		streamExpressionClass(_out, eqClass);
-
-	_out << "Initial stack: " << endl;
-	for (auto const& it: _initialStack)
-	{
-		_out << "  " << dec << it.first << ": ";
-		streamExpressionClass(_out, it.second);
-	}
-	_out << "Target stack: " << endl;
-	for (auto const& it: _targetStack)
-	{
-		_out << "  " << dec << it.first << ": ";
-		streamExpressionClass(_out, it.second);
-	}
-
-	return _out;
-}
-
 void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item, bool _copyItem)
 {
-	if (_item.type() != Operation)
-	{
-		assertThrow(_item.deposit() == 1, InvalidDeposit, "");
-		setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {}, _copyItem));
-	}
-	else
-	{
-		Instruction instruction = _item.instruction();
-		InstructionInfo info = instructionInfo(instruction);
-		if (SemanticInformation::isDupInstruction(_item))
-			setStackElement(
-				m_stackHeight + 1,
-				stackElement(
-					m_stackHeight - int(instruction) + int(Instruction::DUP1),
-					_item.getLocation()
-				)
-			);
-		else if (SemanticInformation::isSwapInstruction(_item))
-			swapStackElements(
-				m_stackHeight,
-				m_stackHeight - 1 - int(instruction) + int(Instruction::SWAP1),
-				_item.getLocation()
-			);
-		else if (instruction != Instruction::POP)
-		{
-			vector arguments(info.args);
-			for (int i = 0; i < info.args; ++i)
-				arguments[i] = stackElement(m_stackHeight - i, _item.getLocation());
-			if (_item.instruction() == Instruction::SSTORE)
-				storeInStorage(arguments[0], arguments[1], _item.getLocation());
-			else if (_item.instruction() == Instruction::SLOAD)
-				setStackElement(
-					m_stackHeight + _item.deposit(),
-					loadFromStorage(arguments[0], _item.getLocation())
-				);
-			else if (_item.instruction() == Instruction::MSTORE)
-				storeInMemory(arguments[0], arguments[1], _item.getLocation());
-			else if (_item.instruction() == Instruction::MLOAD)
-				setStackElement(
-					m_stackHeight + _item.deposit(),
-					loadFromMemory(arguments[0], _item.getLocation())
-				);
-			else if (_item.instruction() == Instruction::SHA3)
-				setStackElement(
-					m_stackHeight + _item.deposit(),
-					applySha3(arguments.at(0), arguments.at(1), _item.getLocation())
-				);
-			else
-				setStackElement(
-					m_stackHeight + _item.deposit(),
-					m_expressionClasses.find(_item, arguments, _copyItem)
-				);
-		}
-		m_stackHeight += _item.deposit();
-	}
+	StoreOperation op = m_state.feedItem(_item, _copyItem);
+	if (op.isValid())
+		m_storeOperations.push_back(op);
 }
 
 void CommonSubexpressionEliminator::optimizeBreakingItem()
@@ -164,20 +73,20 @@ void CommonSubexpressionEliminator::optimizeBreakingItem()
 	SourceLocation const& location = m_breakingItem->getLocation();
 	AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType();
 
-	Id condition = stackElement(m_stackHeight - 1, location);
-	Id zero = m_expressionClasses.find(u256(0));
-	if (m_expressionClasses.knownToBeDifferent(condition, zero))
+	Id condition = m_state.stackElement(m_state.stackHeight() - 1, location);
+	Id zero = m_state.expressionClasses().find(u256(0));
+	if (m_state.expressionClasses().knownToBeDifferent(condition, zero))
 	{
 		feedItem(AssemblyItem(Instruction::SWAP1, location), true);
 		feedItem(AssemblyItem(Instruction::POP, location), true);
 
 		AssemblyItem item(Instruction::JUMP, location);
 		item.setJumpType(jumpType);
-		m_breakingItem = m_expressionClasses.storeItem(item);
+		m_breakingItem = m_state.expressionClasses().storeItem(item);
 		return;
 	}
-	Id negatedCondition = m_expressionClasses.find(Instruction::ISZERO, {condition});
-	if (m_expressionClasses.knownToBeDifferent(negatedCondition, zero))
+	Id negatedCondition = m_state.expressionClasses().find(Instruction::ISZERO, {condition});
+	if (m_state.expressionClasses().knownToBeDifferent(negatedCondition, zero))
 	{
 		AssemblyItem it(Instruction::POP, location);
 		feedItem(it, true);
@@ -186,148 +95,6 @@ void CommonSubexpressionEliminator::optimizeBreakingItem()
 	}
 }
 
-void CommonSubexpressionEliminator::setStackElement(int _stackHeight, Id _class)
-{
-	m_stackElements[_stackHeight] = _class;
-}
-
-void CommonSubexpressionEliminator::swapStackElements(
-	int _stackHeightA,
-	int _stackHeightB,
-	SourceLocation const& _location
-)
-{
-	assertThrow(_stackHeightA != _stackHeightB, OptimizerException, "Swap on same stack elements.");
-	// ensure they are created
-	stackElement(_stackHeightA, _location);
-	stackElement(_stackHeightB, _location);
-
-	swap(m_stackElements[_stackHeightA], m_stackElements[_stackHeightB]);
-}
-
-ExpressionClasses::Id CommonSubexpressionEliminator::stackElement(
-	int _stackHeight,
-	SourceLocation const& _location
-)
-{
-	if (m_stackElements.count(_stackHeight))
-		return m_stackElements.at(_stackHeight);
-	// Stack element not found (not assigned yet), create new equivalence class.
-	return m_stackElements[_stackHeight] = initialStackElement(_stackHeight, _location);
-}
-
-ExpressionClasses::Id CommonSubexpressionEliminator::initialStackElement(
-	int _stackHeight,
-	SourceLocation const& _location
-)
-{
-	assertThrow(_stackHeight <= 0, OptimizerException, "Initial stack element of positive height requested.");
-	assertThrow(_stackHeight > -16, StackTooDeepException, "");
-	// This is a special assembly item that refers to elements pre-existing on the initial stack.
-	return m_expressionClasses.find(AssemblyItem(dupInstruction(1 - _stackHeight), _location));
-}
-
-void CommonSubexpressionEliminator::storeInStorage(Id _slot, Id _value, SourceLocation const& _location)
-{
-	if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value)
-		// do not execute the storage if we know that the value is already there
-		return;
-	m_sequenceNumber++;
-	decltype(m_storageContent) storageContents;
-	// Copy over all values (i.e. retain knowledge about them) where we know that this store
-	// operation will not destroy the knowledge. Specifically, we copy storage locations we know
-	// are different from _slot or locations where we know that the stored value is equal to _value.
-	for (auto const& storageItem: m_storageContent)
-		if (m_expressionClasses.knownToBeDifferent(storageItem.first, _slot) || storageItem.second == _value)
-			storageContents.insert(storageItem);
-	m_storageContent = move(storageContents);
-
-	AssemblyItem item(Instruction::SSTORE, _location);
-	Id id = m_expressionClasses.find(item, {_slot, _value}, true, m_sequenceNumber);
-	m_storeOperations.push_back(StoreOperation(StoreOperation::Storage, _slot, m_sequenceNumber, id));
-	m_storageContent[_slot] = _value;
-	// increment a second time so that we get unique sequence numbers for writes
-	m_sequenceNumber++;
-}
-
-ExpressionClasses::Id CommonSubexpressionEliminator::loadFromStorage(Id _slot, SourceLocation const& _location)
-{
-	if (m_storageContent.count(_slot))
-		return m_storageContent.at(_slot);
-
-	AssemblyItem item(Instruction::SLOAD, _location);
-	return m_storageContent[_slot] = m_expressionClasses.find(item, {_slot}, true, m_sequenceNumber);
-}
-
-void CommonSubexpressionEliminator::storeInMemory(Id _slot, Id _value, SourceLocation const& _location)
-{
-	if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value)
-		// do not execute the store if we know that the value is already there
-		return;
-	m_sequenceNumber++;
-	decltype(m_memoryContent) memoryContents;
-	// copy over values at points where we know that they are different from _slot by at least 32
-	for (auto const& memoryItem: m_memoryContent)
-		if (m_expressionClasses.knownToBeDifferentBy32(memoryItem.first, _slot))
-			memoryContents.insert(memoryItem);
-	m_memoryContent = move(memoryContents);
-
-	AssemblyItem item(Instruction::MSTORE, _location);
-	Id id = m_expressionClasses.find(item, {_slot, _value}, true, m_sequenceNumber);
-	m_storeOperations.push_back(StoreOperation(StoreOperation::Memory, _slot, m_sequenceNumber, id));
-	m_memoryContent[_slot] = _value;
-	// increment a second time so that we get unique sequence numbers for writes
-	m_sequenceNumber++;
-}
-
-ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(Id _slot, SourceLocation const& _location)
-{
-	if (m_memoryContent.count(_slot))
-		return m_memoryContent.at(_slot);
-
-	AssemblyItem item(Instruction::MLOAD, _location);
-	return m_memoryContent[_slot] = m_expressionClasses.find(item, {_slot}, true, m_sequenceNumber);
-}
-
-CommonSubexpressionEliminator::Id CommonSubexpressionEliminator::applySha3(
-	Id _start,
-	Id _length,
-	SourceLocation const& _location
-)
-{
-	AssemblyItem sha3Item(Instruction::SHA3, _location);
-	// Special logic if length is a short constant, otherwise we cannot tell.
-	u256 const* l = m_expressionClasses.knownConstant(_length);
-	// unknown or too large length
-	if (!l || *l > 128)
-		return m_expressionClasses.find(sha3Item, {_start, _length}, true, m_sequenceNumber);
-
-	vector arguments;
-	for (u256 i = 0; i < *l; i += 32)
-	{
-		Id slot = m_expressionClasses.find(
-			AssemblyItem(Instruction::ADD, _location),
-			{_start, m_expressionClasses.find(i)}
-		);
-		arguments.push_back(loadFromMemory(slot, _location));
-	}
-	if (m_knownSha3Hashes.count(arguments))
-		return m_knownSha3Hashes.at(arguments);
-	Id v;
-	// If all arguments are known constants, compute the sha3 here
-	if (all_of(arguments.begin(), arguments.end(), [this](Id _a) { return !!m_expressionClasses.knownConstant(_a); }))
-	{
-		bytes data;
-		for (Id a: arguments)
-			data += toBigEndian(*m_expressionClasses.knownConstant(a));
-		data.resize(size_t(*l));
-		v = m_expressionClasses.find(AssemblyItem(u256(sha3(data)), _location));
-	}
-	else
-		v = m_expressionClasses.find(sha3Item, {_start, _length}, true, m_sequenceNumber);
-	return m_knownSha3Hashes[arguments] = v;
-}
-
 CSECodeGenerator::CSECodeGenerator(
 	ExpressionClasses& _expressionClasses,
 	vector const& _storeOperations
diff --git a/libevmasm/CommonSubexpressionEliminator.h b/libevmasm/CommonSubexpressionEliminator.h
index 6156bc81a..2ed926401 100644
--- a/libevmasm/CommonSubexpressionEliminator.h
+++ b/libevmasm/CommonSubexpressionEliminator.h
@@ -32,6 +32,7 @@
 #include 
 #include 
 #include 
+#include 
 
 namespace dev
 {
@@ -58,20 +59,9 @@ class CommonSubexpressionEliminator
 {
 public:
 	using Id = ExpressionClasses::Id;
-	struct StoreOperation
-	{
-		enum Target { Memory, Storage };
-		StoreOperation(
-			Target _target,
-			Id _slot,
-			unsigned _sequenceNumber,
-			Id _expression
-		): target(_target), slot(_slot), sequenceNumber(_sequenceNumber), expression(_expression) {}
-		Target target;
-		Id slot;
-		unsigned sequenceNumber;
-		Id expression;
-	};
+	using StoreOperation = KnownState::StoreOperation;
+
+	CommonSubexpressionEliminator(KnownState const& _state): m_state(_state) {}
 
 	/// Feeds AssemblyItems into the eliminator and @returns the iterator pointing at the first
 	/// item that must be fed into a new instance of the eliminator.
@@ -95,49 +85,10 @@ private:
 	/// Tries to optimize the item that breaks the basic block at the end.
 	void optimizeBreakingItem();
 
-	/// Simplifies the given item using
-	/// Assigns a new equivalence class to the next sequence number of the given stack element.
-	void setStackElement(int _stackHeight, Id _class);
-	/// Swaps the given stack elements in their next sequence number.
-	void swapStackElements(int _stackHeightA, int _stackHeightB, SourceLocation const& _location);
-	/// Retrieves the current equivalence class fo the given stack element (or generates a new
-	/// one if it does not exist yet).
-	Id stackElement(int _stackHeight, SourceLocation const& _location);
-	/// @returns the equivalence class id of the special initial stack element at the given height
-	/// (must not be positive).
-	Id initialStackElement(int _stackHeight, SourceLocation const& _location);
-
-	/// Increments the sequence number, deletes all storage information that might be overwritten
-	/// and stores the new value at the given slot.
-	void storeInStorage(Id _slot, Id _value, SourceLocation const& _location);
-	/// Retrieves the current value at the given slot in storage or creates a new special sload class.
-	Id loadFromStorage(Id _slot, SourceLocation const& _location);
-	/// Increments the sequence number, deletes all memory information that might be overwritten
-	/// and stores the new value at the given slot.
-	void storeInMemory(Id _slot, Id _value, SourceLocation const& _location);
-	/// Retrieves the current value at the given slot in memory or creates a new special mload class.
-	Id loadFromMemory(Id _slot, SourceLocation const& _location);
-	/// Finds or creates a new expression that applies the sha3 hash function to the contents in memory.
-	Id applySha3(Id _start, Id _length, SourceLocation const& _location);
-
-	/// Current stack height, can be negative.
-	int m_stackHeight = 0;
-	/// Current stack layout, mapping stack height -> equivalence class
-	std::map m_stackElements;
-	/// Current sequence number, this is incremented with each modification to storage or memory.
-	unsigned m_sequenceNumber = 1;
-	/// Knowledge about storage content.
-	std::map m_storageContent;
-	/// Knowledge about memory content. Keys are memory addresses, note that the values overlap
-	/// and are not contained here if they are not completely known.
-	std::map m_memoryContent;
-	/// Keeps record of all sha3 hashes that are computed.
-	std::map, Id> m_knownSha3Hashes;
+	KnownState m_state;
 	/// Keeps information about which storage or memory slots were written to at which sequence
 	/// number with what instruction.
 	std::vector m_storeOperations;
-	/// Structure containing the classes of equivalent expressions.
-	ExpressionClasses m_expressionClasses;
 
 	/// The item that breaks the basic block, can be nullptr.
 	/// It is usually appended to the block but can be optimized in some cases.
diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp
new file mode 100644
index 000000000..244270fb6
--- /dev/null
+++ b/libevmasm/KnownState.cpp
@@ -0,0 +1,278 @@
+/*
+	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 KnownState.cpp
+ * @author Christian 
+ * @date 2015
+ * Contains knowledge about the state of the virtual machine at a specific instruction.
+ */
+
+#include "KnownState.h"
+#include 
+#include 
+#include 
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+
+ostream& KnownState::stream(
+	ostream& _out,
+	map _initialStack,
+	map _targetStack
+) const
+{
+	auto streamExpressionClass = [this](ostream& _out, Id _id)
+	{
+		auto const& expr = m_expressionClasses->representative(_id);
+		_out << "  " << dec << _id << ": " << *expr.item;
+		if (expr.sequenceNumber)
+			_out << "@" << dec << expr.sequenceNumber;
+		_out << "(";
+		for (Id arg: expr.arguments)
+			_out << dec << arg << ",";
+		_out << ")" << endl;
+	};
+
+	_out << "Optimizer analysis:" << endl;
+	_out << "Final stack height: " << dec << m_stackHeight << endl;
+	_out << "Equivalence classes: " << endl;
+	for (Id eqClass = 0; eqClass < m_expressionClasses->size(); ++eqClass)
+		streamExpressionClass(_out, eqClass);
+
+	_out << "Initial stack: " << endl;
+	for (auto const& it: _initialStack)
+	{
+		_out << "  " << dec << it.first << ": ";
+		streamExpressionClass(_out, it.second);
+	}
+	_out << "Target stack: " << endl;
+	for (auto const& it: _targetStack)
+	{
+		_out << "  " << dec << it.first << ": ";
+		streamExpressionClass(_out, it.second);
+	}
+
+	return _out;
+}
+
+KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool _copyItem)
+{
+	StoreOperation op;
+	if (_item.type() != Operation)
+	{
+		assertThrow(_item.deposit() == 1, InvalidDeposit, "");
+		setStackElement(++m_stackHeight, m_expressionClasses->find(_item, {}, _copyItem));
+	}
+	else
+	{
+		Instruction instruction = _item.instruction();
+		InstructionInfo info = instructionInfo(instruction);
+		if (SemanticInformation::isDupInstruction(_item))
+			setStackElement(
+				m_stackHeight + 1,
+				stackElement(
+					m_stackHeight - int(instruction) + int(Instruction::DUP1),
+					_item.getLocation()
+				)
+			);
+		else if (SemanticInformation::isSwapInstruction(_item))
+			swapStackElements(
+				m_stackHeight,
+				m_stackHeight - 1 - int(instruction) + int(Instruction::SWAP1),
+				_item.getLocation()
+			);
+		else if (instruction != Instruction::POP)
+		{
+			vector arguments(info.args);
+			for (int i = 0; i < info.args; ++i)
+				arguments[i] = stackElement(m_stackHeight - i, _item.getLocation());
+			if (_item.instruction() == Instruction::SSTORE)
+				op = storeInStorage(arguments[0], arguments[1], _item.getLocation());
+			else if (_item.instruction() == Instruction::SLOAD)
+				setStackElement(
+					m_stackHeight + _item.deposit(),
+					loadFromStorage(arguments[0], _item.getLocation())
+				);
+			else if (_item.instruction() == Instruction::MSTORE)
+				op = storeInMemory(arguments[0], arguments[1], _item.getLocation());
+			else if (_item.instruction() == Instruction::MLOAD)
+				setStackElement(
+					m_stackHeight + _item.deposit(),
+					loadFromMemory(arguments[0], _item.getLocation())
+				);
+			else if (_item.instruction() == Instruction::SHA3)
+				setStackElement(
+					m_stackHeight + _item.deposit(),
+					applySha3(arguments.at(0), arguments.at(1), _item.getLocation())
+				);
+			else
+				setStackElement(
+					m_stackHeight + _item.deposit(),
+					m_expressionClasses->find(_item, arguments, _copyItem)
+				);
+		}
+		m_stackHeight += _item.deposit();
+	}
+	return op;
+}
+
+ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation const& _location)
+{
+	if (m_stackElements.count(_stackHeight))
+		return m_stackElements.at(_stackHeight);
+	// Stack element not found (not assigned yet), create new equivalence class.
+	return m_stackElements[_stackHeight] = initialStackElement(_stackHeight, _location);
+}
+
+ExpressionClasses::Id KnownState::initialStackElement(
+	int _stackHeight,
+	SourceLocation const& _location
+)
+{
+	assertThrow(_stackHeight <= 0, OptimizerException, "Initial stack element of positive height requested.");
+	assertThrow(_stackHeight > -16, StackTooDeepException, "");
+	// This is a special assembly item that refers to elements pre-existing on the initial stack.
+	return m_expressionClasses->find(AssemblyItem(dupInstruction(1 - _stackHeight), _location));
+}
+
+void KnownState::setStackElement(int _stackHeight, Id _class)
+{
+	m_stackElements[_stackHeight] = _class;
+}
+
+void KnownState::swapStackElements(
+	int _stackHeightA,
+	int _stackHeightB,
+	SourceLocation const& _location
+)
+{
+	assertThrow(_stackHeightA != _stackHeightB, OptimizerException, "Swap on same stack elements.");
+	// ensure they are created
+	stackElement(_stackHeightA, _location);
+	stackElement(_stackHeightB, _location);
+
+	swap(m_stackElements[_stackHeightA], m_stackElements[_stackHeightB]);
+}
+
+KnownState::StoreOperation KnownState::storeInStorage(
+	Id _slot,
+	Id _value,
+	SourceLocation const& _location)
+{
+	if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value)
+		// do not execute the storage if we know that the value is already there
+		return StoreOperation();
+	m_sequenceNumber++;
+	decltype(m_storageContent) storageContents;
+	// Copy over all values (i.e. retain knowledge about them) where we know that this store
+	// operation will not destroy the knowledge. Specifically, we copy storage locations we know
+	// are different from _slot or locations where we know that the stored value is equal to _value.
+	for (auto const& storageItem: m_storageContent)
+		if (m_expressionClasses->knownToBeDifferent(storageItem.first, _slot) || storageItem.second == _value)
+			storageContents.insert(storageItem);
+	m_storageContent = move(storageContents);
+
+	AssemblyItem item(Instruction::SSTORE, _location);
+	Id id = m_expressionClasses->find(item, {_slot, _value}, true, m_sequenceNumber);
+	StoreOperation operation(StoreOperation::Storage, _slot, m_sequenceNumber, id);
+	m_storageContent[_slot] = _value;
+	// increment a second time so that we get unique sequence numbers for writes
+	m_sequenceNumber++;
+
+	return operation;
+}
+
+ExpressionClasses::Id KnownState::loadFromStorage(Id _slot, SourceLocation const& _location)
+{
+	if (m_storageContent.count(_slot))
+		return m_storageContent.at(_slot);
+
+	AssemblyItem item(Instruction::SLOAD, _location);
+	return m_storageContent[_slot] = m_expressionClasses->find(item, {_slot}, true, m_sequenceNumber);
+}
+
+KnownState::StoreOperation KnownState::storeInMemory(Id _slot, Id _value, SourceLocation const& _location)
+{
+	if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value)
+		// do not execute the store if we know that the value is already there
+		return StoreOperation();
+	m_sequenceNumber++;
+	decltype(m_memoryContent) memoryContents;
+	// copy over values at points where we know that they are different from _slot by at least 32
+	for (auto const& memoryItem: m_memoryContent)
+		if (m_expressionClasses->knownToBeDifferentBy32(memoryItem.first, _slot))
+			memoryContents.insert(memoryItem);
+	m_memoryContent = move(memoryContents);
+
+	AssemblyItem item(Instruction::MSTORE, _location);
+	Id id = m_expressionClasses->find(item, {_slot, _value}, true, m_sequenceNumber);
+	StoreOperation operation(StoreOperation(StoreOperation::Memory, _slot, m_sequenceNumber, id));
+	m_memoryContent[_slot] = _value;
+	// increment a second time so that we get unique sequence numbers for writes
+	m_sequenceNumber++;
+	return operation;
+}
+
+ExpressionClasses::Id KnownState::loadFromMemory(Id _slot, SourceLocation const& _location)
+{
+	if (m_memoryContent.count(_slot))
+		return m_memoryContent.at(_slot);
+
+	AssemblyItem item(Instruction::MLOAD, _location);
+	return m_memoryContent[_slot] = m_expressionClasses->find(item, {_slot}, true, m_sequenceNumber);
+}
+
+KnownState::Id KnownState::applySha3(
+	Id _start,
+	Id _length,
+	SourceLocation const& _location
+)
+{
+	AssemblyItem sha3Item(Instruction::SHA3, _location);
+	// Special logic if length is a short constant, otherwise we cannot tell.
+	u256 const* l = m_expressionClasses->knownConstant(_length);
+	// unknown or too large length
+	if (!l || *l > 128)
+		return m_expressionClasses->find(sha3Item, {_start, _length}, true, m_sequenceNumber);
+
+	vector arguments;
+	for (u256 i = 0; i < *l; i += 32)
+	{
+		Id slot = m_expressionClasses->find(
+			AssemblyItem(Instruction::ADD, _location),
+			{_start, m_expressionClasses->find(i)}
+		);
+		arguments.push_back(loadFromMemory(slot, _location));
+	}
+	if (m_knownSha3Hashes.count(arguments))
+		return m_knownSha3Hashes.at(arguments);
+	Id v;
+	// If all arguments are known constants, compute the sha3 here
+	if (all_of(arguments.begin(), arguments.end(), [this](Id _a) { return !!m_expressionClasses->knownConstant(_a); }))
+	{
+		bytes data;
+		for (Id a: arguments)
+			data += toBigEndian(*m_expressionClasses->knownConstant(a));
+		data.resize(size_t(*l));
+		v = m_expressionClasses->find(AssemblyItem(u256(sha3(data)), _location));
+	}
+	else
+		v = m_expressionClasses->find(sha3Item, {_start, _length}, true, m_sequenceNumber);
+	return m_knownSha3Hashes[arguments] = v;
+}
+
diff --git a/libevmasm/KnownState.h b/libevmasm/KnownState.h
new file mode 100644
index 000000000..c6dfcee6b
--- /dev/null
+++ b/libevmasm/KnownState.h
@@ -0,0 +1,149 @@
+/*
+	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 KnownState.h
+ * @author Christian 
+ * @date 2015
+ * Contains knowledge about the state of the virtual machine at a specific instruction.
+ */
+
+#pragma once
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace dev
+{
+namespace eth
+{
+
+class AssemblyItem;
+using AssemblyItems = std::vector;
+
+/**
+ * Class to infer and store knowledge about the state of the virtual machine at a specific
+ * instruction.
+ *
+ * The general workings are that for each assembly item that is fed, an equivalence class is
+ * derived from the operation and the equivalence class of its arguments. DUPi, SWAPi and some
+ * arithmetic instructions are used to infer equivalences while these classes are determined.
+ */
+class KnownState
+{
+public:
+	using Id = ExpressionClasses::Id;
+	struct StoreOperation
+	{
+		enum Target { Invalid, Memory, Storage };
+		StoreOperation(): target(Invalid), sequenceNumber(-1) {}
+		StoreOperation(
+			Target _target,
+			Id _slot,
+			unsigned _sequenceNumber,
+			Id _expression
+		): target(_target), slot(_slot), sequenceNumber(_sequenceNumber), expression(_expression) {}
+		bool isValid() const { return target != Invalid; }
+		Target target;
+		Id slot;
+		unsigned sequenceNumber;
+		Id expression;
+	};
+
+	KnownState(): m_expressionClasses(std::make_shared()) {}
+
+	/// Streams debugging information to @a _out.
+	std::ostream& stream(
+		std::ostream& _out,
+		std::map _initialStack = std::map(),
+		std::map _targetStack = std::map()
+	) const;
+
+	/// Feeds the item into the system for analysis.
+	/// @returns a possible store operation
+	StoreOperation feedItem(AssemblyItem const& _item, bool _copyItem = false);
+
+	/// Resets any knowledge about storage.
+	void resetStorage() { m_storageContent.clear(); }
+	/// Resets any knowledge about storage.
+	void resetMemory() { m_memoryContent.clear(); }
+	/// Resets any knowledge about the current stack.
+	void resetStack() { m_stackElements.clear(); m_stackHeight = 0; }
+	/// Resets any knowledge.
+	void reset() { resetStorage(); resetMemory(); resetStack(); }
+
+	///@todo the sequence numbers in two copies of this class should never be the same.
+	/// might be doable using two-dimensional sequence numbers, where the first value is incremented
+	/// for each copy
+
+	/// Retrieves the current equivalence class fo the given stack element (or generates a new
+	/// one if it does not exist yet).
+	Id stackElement(int _stackHeight, SourceLocation const& _location);
+	/// @returns the equivalence class id of the special initial stack element at the given height
+	/// (must not be positive).
+	Id initialStackElement(int _stackHeight, SourceLocation const& _location);
+
+	int stackHeight() const { return m_stackHeight; }
+	std::map const& stackElements() const { return m_stackElements; }
+	ExpressionClasses& expressionClasses() const { return *m_expressionClasses; }
+
+private:
+	/// Assigns a new equivalence class to the next sequence number of the given stack element.
+	void setStackElement(int _stackHeight, Id _class);
+	/// Swaps the given stack elements in their next sequence number.
+	void swapStackElements(int _stackHeightA, int _stackHeightB, SourceLocation const& _location);
+
+	/// Increments the sequence number, deletes all storage information that might be overwritten
+	/// and stores the new value at the given slot.
+	/// @returns the store operation, which might be invalid if storage was not modified
+	StoreOperation storeInStorage(Id _slot, Id _value, SourceLocation const& _location);
+	/// Retrieves the current value at the given slot in storage or creates a new special sload class.
+	Id loadFromStorage(Id _slot, SourceLocation const& _location);
+	/// Increments the sequence number, deletes all memory information that might be overwritten
+	/// and stores the new value at the given slot.
+	/// @returns the store operation, which might be invalid if memory was not modified
+	StoreOperation storeInMemory(Id _slot, Id _value, SourceLocation const& _location);
+	/// Retrieves the current value at the given slot in memory or creates a new special mload class.
+	Id loadFromMemory(Id _slot, SourceLocation const& _location);
+	/// Finds or creates a new expression that applies the sha3 hash function to the contents in memory.
+	Id applySha3(Id _start, Id _length, SourceLocation const& _location);
+
+	/// Current stack height, can be negative.
+	int m_stackHeight = 0;
+	/// Current stack layout, mapping stack height -> equivalence class
+	std::map m_stackElements;
+	/// Current sequence number, this is incremented with each modification to storage or memory.
+	unsigned m_sequenceNumber = 1;
+	/// Knowledge about storage content.
+	std::map m_storageContent;
+	/// Knowledge about memory content. Keys are memory addresses, note that the values overlap
+	/// and are not contained here if they are not completely known.
+	std::map m_memoryContent;
+	/// Keeps record of all sha3 hashes that are computed.
+	std::map, Id> m_knownSha3Hashes;
+	/// Structure containing the classes of equivalent expressions.
+	std::shared_ptr m_expressionClasses;
+};
+
+}
+}
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index 9cdaa5886..71463f919 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -90,7 +90,8 @@ public:
 		for (AssemblyItem& item: input)
 			item.setLocation(SourceLocation(1, 3, make_shared("")));
 
-		eth::CommonSubexpressionEliminator cse;
+		eth::KnownState state;
+		eth::CommonSubexpressionEliminator cse(state);
 		BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end());
 		AssemblyItems output = cse.getOptimizedItems();
 
@@ -231,7 +232,8 @@ BOOST_AUTO_TEST_CASE(function_calls)
 
 BOOST_AUTO_TEST_CASE(cse_intermediate_swap)
 {
-	eth::CommonSubexpressionEliminator cse;
+	eth::KnownState state;
+	eth::CommonSubexpressionEliminator cse(state);
 	AssemblyItems input{
 		Instruction::SWAP1, Instruction::POP, Instruction::ADD, u256(0), Instruction::SWAP1,
 		Instruction::SLOAD, Instruction::SWAP1, u256(100), Instruction::EXP, Instruction::SWAP1,

From ce15b5bbc9df87c72aaf3faa28f91db17f6cb624 Mon Sep 17 00:00:00 2001
From: chriseth 
Date: Thu, 30 Apr 2015 11:40:43 +0200
Subject: [PATCH 37/87] More flexible way to approach unknown stack elements.

---
 libevmasm/ExpressionClasses.cpp | 36 ++++++++++++++++++++++++---------
 libevmasm/ExpressionClasses.h   |  8 ++++++--
 libevmasm/KnownState.cpp        |  2 +-
 3 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp
index 1e60a7fe8..8d0785d37 100644
--- a/libevmasm/ExpressionClasses.cpp
+++ b/libevmasm/ExpressionClasses.cpp
@@ -37,6 +37,7 @@ using namespace dev::eth;
 
 bool ExpressionClasses::Expression::operator<(ExpressionClasses::Expression const& _other) const
 {
+	assertThrow(!!item && !!_other.item, OptimizerException, "");
 	auto type = item->type();
 	auto otherType = _other.item->type();
 	return std::tie(type, item->data(), arguments, sequenceNumber) <
@@ -78,6 +79,15 @@ ExpressionClasses::Id ExpressionClasses::find(
 	return exp.id;
 }
 
+ExpressionClasses::Id ExpressionClasses::newId()
+{
+	// Note that we cannot insert it in m_expressions because this requires item to be set.
+	Expression exp;
+	exp.id = m_representatives.size();
+	m_representatives.push_back(exp);
+	return exp.id;
+}
+
 bool ExpressionClasses::knownToBeDifferent(ExpressionClasses::Id _a, ExpressionClasses::Id _b)
 {
 	// Try to simplify "_a - _b" and return true iff the value is a non-zero constant.
@@ -122,10 +132,16 @@ string ExpressionClasses::fullDAGToString(ExpressionClasses::Id _id) const
 {
 	Expression const& expr = representative(_id);
 	stringstream str;
-	str << dec << expr.id << ":" << *expr.item << "(";
-	for (Id arg: expr.arguments)
-		str << fullDAGToString(arg) << ",";
-	str << ")";
+	str << dec << expr.id << ":";
+	if (expr.item)
+	{
+		str << *expr.item << "(";
+		for (Id arg: expr.arguments)
+			str << fullDAGToString(arg) << ",";
+		str << ")";
+	}
+	else
+		str << " UNIQUE";
 	return str.str();
 }
 
@@ -279,7 +295,7 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr,
 {
 	static Rules rules;
 
-	if (_expr.item->type() != Operation)
+	if (!_expr.item || _expr.item->type() != Operation)
 		return -1;
 
 	for (auto const& rule: rules.rules())
@@ -337,7 +353,7 @@ void Pattern::setMatchGroup(unsigned _group, map& _
 
 bool Pattern::matches(Expression const& _expr, ExpressionClasses const& _classes) const
 {
-	if (!matchesBaseItem(*_expr.item))
+	if (!matchesBaseItem(_expr.item))
 		return false;
 	if (m_matchGroup)
 	{
@@ -387,13 +403,15 @@ string Pattern::toString() const
 	return s.str();
 }
 
-bool Pattern::matchesBaseItem(AssemblyItem const& _item) const
+bool Pattern::matchesBaseItem(AssemblyItem const* _item) const
 {
 	if (m_type == UndefinedItem)
 		return true;
-	if (m_type != _item.type())
+	if (!_item)
+		return false;
+	if (m_type != _item->type())
 		return false;
-	if (m_requireDataMatch && m_data != _item.data())
+	if (m_requireDataMatch && m_data != _item->data())
 		return false;
 	return true;
 }
diff --git a/libevmasm/ExpressionClasses.h b/libevmasm/ExpressionClasses.h
index 2f720f606..5d32c0f71 100644
--- a/libevmasm/ExpressionClasses.h
+++ b/libevmasm/ExpressionClasses.h
@@ -50,7 +50,7 @@ public:
 	struct Expression
 	{
 		Id id;
-		AssemblyItem const* item;
+		AssemblyItem const* item = nullptr;
 		Ids arguments;
 		unsigned sequenceNumber; ///< Storage modification sequence, only used for SLOAD/SSTORE instructions.
 		/// Behaves as if this was a tuple of (item->type(), item->data(), arguments, sequenceNumber).
@@ -68,6 +68,10 @@ public:
 		bool _copyItem = true,
 		unsigned _sequenceNumber = 0
 	);
+	/// @returns a new unique class id which does not and will never have a representative containing
+	/// an AssemblyItem, i.e. its value cannot be generated, instead it has to be assumed to be
+	/// already present.
+	Id newId();
 	/// @returns the canonical representative of an expression class.
 	Expression const& representative(Id _id) const { return m_representatives.at(_id); }
 	/// @returns the number of classes.
@@ -149,7 +153,7 @@ public:
 	std::string toString() const;
 
 private:
-	bool matchesBaseItem(AssemblyItem const& _item) const;
+	bool matchesBaseItem(AssemblyItem const* _item) const;
 	Expression const& matchGroupValue() const;
 
 	AssemblyItemType m_type;
diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp
index 244270fb6..e83810d43 100644
--- a/libevmasm/KnownState.cpp
+++ b/libevmasm/KnownState.cpp
@@ -136,7 +136,7 @@ ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation
 	if (m_stackElements.count(_stackHeight))
 		return m_stackElements.at(_stackHeight);
 	// Stack element not found (not assigned yet), create new equivalence class.
-	return m_stackElements[_stackHeight] = initialStackElement(_stackHeight, _location);
+	return m_stackElements[_stackHeight] = m_expressionClasses->newId();
 }
 
 ExpressionClasses::Id KnownState::initialStackElement(

From e768959342dca9320670874fbdd353b8789854e8 Mon Sep 17 00:00:00 2001
From: chriseth 
Date: Thu, 30 Apr 2015 14:41:55 +0200
Subject: [PATCH 38/87] Common subexpression elimination ready for using
 pre-known state.

---
 libevmasm/CommonSubexpressionEliminator.cpp |  8 ++--
 libevmasm/CommonSubexpressionEliminator.h   |  6 ++-
 libevmasm/ExpressionClasses.cpp             |  9 ----
 libevmasm/ExpressionClasses.h               |  4 --
 libevmasm/KnownState.cpp                    | 10 ++---
 test/libsolidity/SolidityOptimizer.cpp      | 49 +++++++++++++++++++--
 6 files changed, 59 insertions(+), 27 deletions(-)

diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp
index 645a426d9..4b85eba40 100644
--- a/libevmasm/CommonSubexpressionEliminator.cpp
+++ b/libevmasm/CommonSubexpressionEliminator.cpp
@@ -40,9 +40,8 @@ vector CommonSubexpressionEliminator::getOptimizedItems()
 	int minHeight = m_state.stackHeight() + 1;
 	if (!m_state.stackElements().empty())
 		minHeight = min(minHeight, m_state.stackElements().begin()->first);
-	for (int height = minHeight; height <= 0; ++height)
-		//@todo this is not nice as it is here - should be "unknownStackElement" - but is it really unknown?
-		initialStackContents[height] = m_state.initialStackElement(height, SourceLocation());
+	for (int height = minHeight; height <= m_initialState.stackHeight(); ++height)
+		initialStackContents[height] = m_initialState.stackElement(height, SourceLocation());
 	for (int height = minHeight; height <= m_state.stackHeight(); ++height)
 		targetStackContents[height] = m_state.stackElement(height, SourceLocation());
 
@@ -50,6 +49,7 @@ vector CommonSubexpressionEliminator::getOptimizedItems()
 	//stream(cout, initialStackContents, targetStackContents);
 
 	AssemblyItems items = CSECodeGenerator(m_state.expressionClasses(), m_storeOperations).generateCode(
+		m_initialState.stackHeight(),
 		initialStackContents,
 		targetStackContents
 	);
@@ -106,10 +106,12 @@ CSECodeGenerator::CSECodeGenerator(
 }
 
 AssemblyItems CSECodeGenerator::generateCode(
+	int _initialStackHeight,
 	map const& _initialStack,
 	map const& _targetStackContents
 )
 {
+	m_stackHeight = _initialStackHeight;
 	m_stack = _initialStack;
 	for (auto const& item: m_stack)
 		if (!m_classPositions.count(item.second))
diff --git a/libevmasm/CommonSubexpressionEliminator.h b/libevmasm/CommonSubexpressionEliminator.h
index 2ed926401..6e1ba40b3 100644
--- a/libevmasm/CommonSubexpressionEliminator.h
+++ b/libevmasm/CommonSubexpressionEliminator.h
@@ -61,7 +61,7 @@ public:
 	using Id = ExpressionClasses::Id;
 	using StoreOperation = KnownState::StoreOperation;
 
-	CommonSubexpressionEliminator(KnownState const& _state): m_state(_state) {}
+	CommonSubexpressionEliminator(KnownState const& _state): m_initialState(_state), m_state(_state) {}
 
 	/// Feeds AssemblyItems into the eliminator and @returns the iterator pointing at the first
 	/// item that must be fed into a new instance of the eliminator.
@@ -85,6 +85,7 @@ private:
 	/// Tries to optimize the item that breaks the basic block at the end.
 	void optimizeBreakingItem();
 
+	KnownState m_initialState;
 	KnownState m_state;
 	/// Keeps information about which storage or memory slots were written to at which sequence
 	/// number with what instruction.
@@ -115,6 +116,7 @@ public:
 	/// @param _targetStackContents final contents of the stack, by stack height relative to initial
 	/// @note should only be called once on each object.
 	AssemblyItems generateCode(
+		int _initialStackHeight,
 		std::map const& _initialStack,
 		std::map const& _targetStackContents
 	);
@@ -150,7 +152,7 @@ private:
 
 	AssemblyItems m_generatedItems;
 	/// Current height of the stack relative to the start.
-	int m_stackHeight = 0;
+	int m_stackHeight;
 	/// If (b, a) is in m_requests then b is needed to compute a.
 	std::multimap m_neededBy;
 	/// Current content of the stack.
diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp
index 8d0785d37..e62f75264 100644
--- a/libevmasm/ExpressionClasses.cpp
+++ b/libevmasm/ExpressionClasses.cpp
@@ -79,15 +79,6 @@ ExpressionClasses::Id ExpressionClasses::find(
 	return exp.id;
 }
 
-ExpressionClasses::Id ExpressionClasses::newId()
-{
-	// Note that we cannot insert it in m_expressions because this requires item to be set.
-	Expression exp;
-	exp.id = m_representatives.size();
-	m_representatives.push_back(exp);
-	return exp.id;
-}
-
 bool ExpressionClasses::knownToBeDifferent(ExpressionClasses::Id _a, ExpressionClasses::Id _b)
 {
 	// Try to simplify "_a - _b" and return true iff the value is a non-zero constant.
diff --git a/libevmasm/ExpressionClasses.h b/libevmasm/ExpressionClasses.h
index 5d32c0f71..c83520300 100644
--- a/libevmasm/ExpressionClasses.h
+++ b/libevmasm/ExpressionClasses.h
@@ -68,10 +68,6 @@ public:
 		bool _copyItem = true,
 		unsigned _sequenceNumber = 0
 	);
-	/// @returns a new unique class id which does not and will never have a representative containing
-	/// an AssemblyItem, i.e. its value cannot be generated, instead it has to be assumed to be
-	/// already present.
-	Id newId();
 	/// @returns the canonical representative of an expression class.
 	Expression const& representative(Id _id) const { return m_representatives.at(_id); }
 	/// @returns the number of classes.
diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp
index e83810d43..02c6ee136 100644
--- a/libevmasm/KnownState.cpp
+++ b/libevmasm/KnownState.cpp
@@ -135,8 +135,10 @@ ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation
 {
 	if (m_stackElements.count(_stackHeight))
 		return m_stackElements.at(_stackHeight);
-	// Stack element not found (not assigned yet), create new equivalence class.
-	return m_stackElements[_stackHeight] = m_expressionClasses->newId();
+	// Stack element not found (not assigned yet), create new unknown equivalence class.
+	//@todo check that we do not infer incorrect equivalences when the stack is cleared partially
+	//in between.
+	return m_stackElements[_stackHeight] = initialStackElement(_stackHeight, _location);
 }
 
 ExpressionClasses::Id KnownState::initialStackElement(
@@ -144,10 +146,8 @@ ExpressionClasses::Id KnownState::initialStackElement(
 	SourceLocation const& _location
 )
 {
-	assertThrow(_stackHeight <= 0, OptimizerException, "Initial stack element of positive height requested.");
-	assertThrow(_stackHeight > -16, StackTooDeepException, "");
 	// This is a special assembly item that refers to elements pre-existing on the initial stack.
-	return m_expressionClasses->find(AssemblyItem(dupInstruction(1 - _stackHeight), _location));
+	return m_expressionClasses->find(AssemblyItem(UndefinedItem, u256(_stackHeight), _location));
 }
 
 void KnownState::setStackElement(int _stackHeight, Id _class)
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index 71463f919..59e8f04a8 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -83,15 +83,28 @@ public:
 							"\nOptimized:     " + toHex(optimizedOutput));
 	}
 
-	AssemblyItems getCSE(AssemblyItems const& _input)
+	AssemblyItems addDummyLocations(AssemblyItems const& _input)
 	{
 		// add dummy locations to each item so that we can check that they are not deleted
 		AssemblyItems input = _input;
 		for (AssemblyItem& item: input)
 			item.setLocation(SourceLocation(1, 3, make_shared("")));
+		return input;
+	}
 
+	eth::KnownState createInitialState(AssemblyItems const& _input)
+	{
 		eth::KnownState state;
-		eth::CommonSubexpressionEliminator cse(state);
+		for (auto const& item: addDummyLocations(_input))
+			state.feedItem(item);
+		return state;
+	}
+
+	AssemblyItems getCSE(AssemblyItems const& _input, eth::KnownState const& _state = eth::KnownState())
+	{
+		AssemblyItems input = addDummyLocations(_input);
+
+		eth::CommonSubexpressionEliminator cse(_state);
 		BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end());
 		AssemblyItems output = cse.getOptimizedItems();
 
@@ -102,9 +115,13 @@ public:
 		return output;
 	}
 
-	void checkCSE(AssemblyItems const& _input, AssemblyItems const& _expectation)
+	void checkCSE(
+		AssemblyItems const& _input,
+		AssemblyItems const& _expectation,
+		KnownState const& _state = eth::KnownState()
+	)
 	{
-		AssemblyItems output = getCSE(_input);
+		AssemblyItems output = getCSE(_input, _state);
 		BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
 	}
 
@@ -756,6 +773,30 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_noninterfering_store_in_between
 	BOOST_CHECK_EQUAL(1, count(output.begin(), output.end(), AssemblyItem(Instruction::SHA3)));
 }
 
+BOOST_AUTO_TEST_CASE(cse_with_initially_known_stack)
+{
+	eth::KnownState state = createInitialState(AssemblyItems{
+		u256(0x12),
+		u256(0x20),
+		Instruction::ADD
+	});
+	AssemblyItems input{
+		u256(0x12 + 0x20)
+	};
+	checkCSE(input, AssemblyItems{Instruction::DUP1}, state);
+}
+
+BOOST_AUTO_TEST_CASE(cse_equality_on_initially_known_stack)
+{
+	eth::KnownState state = createInitialState(AssemblyItems{Instruction::DUP1});
+	AssemblyItems input{
+		Instruction::EQ
+	};
+	AssemblyItems output = getCSE(input, state);
+	// check that it directly pushes 1 (true)
+	BOOST_CHECK(find(output.begin(), output.end(), AssemblyItem(u256(1))) != output.end());
+}
+
 BOOST_AUTO_TEST_CASE(control_flow_graph_remove_unused)
 {
 	// remove parts of the code that are unused

From 4988a6766fb26a47320725138451ff6b477b9018 Mon Sep 17 00:00:00 2001
From: chriseth 
Date: Thu, 30 Apr 2015 15:31:16 +0200
Subject: [PATCH 39/87] Make KnownState work with all instructions.

---
 libevmasm/ExpressionClasses.cpp   | 19 +++++++----
 libevmasm/KnownState.cpp          |  7 ++++
 libevmasm/SemanticInformation.cpp | 54 +++++++++++++++++++++++++++++++
 libevmasm/SemanticInformation.h   |  9 ++++++
 4 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp
index e62f75264..cfbeba7fa 100644
--- a/libevmasm/ExpressionClasses.cpp
+++ b/libevmasm/ExpressionClasses.cpp
@@ -57,12 +57,15 @@ ExpressionClasses::Id ExpressionClasses::find(
 	exp.arguments = _arguments;
 	exp.sequenceNumber = _sequenceNumber;
 
-	if (SemanticInformation::isCommutativeOperation(_item))
-		sort(exp.arguments.begin(), exp.arguments.end());
+	if (SemanticInformation::isDeterministic(_item))
+	{
+		if (SemanticInformation::isCommutativeOperation(_item))
+			sort(exp.arguments.begin(), exp.arguments.end());
 
-	auto it = m_expressions.find(exp);
-	if (it != m_expressions.end())
-		return it->id;
+		auto it = m_expressions.find(exp);
+		if (it != m_expressions.end())
+			return it->id;
+	}
 
 	if (_copyItem)
 		exp.item = storeItem(_item);
@@ -286,7 +289,11 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr,
 {
 	static Rules rules;
 
-	if (!_expr.item || _expr.item->type() != Operation)
+	if (
+		!_expr.item ||
+		_expr.item->type() != Operation ||
+		!SemanticInformation::isDeterministic(*_expr.item)
+	)
 		return -1;
 
 	for (auto const& rule: rules.rules())
diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp
index 02c6ee136..632777c82 100644
--- a/libevmasm/KnownState.cpp
+++ b/libevmasm/KnownState.cpp
@@ -101,6 +101,7 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
 			vector arguments(info.args);
 			for (int i = 0; i < info.args; ++i)
 				arguments[i] = stackElement(m_stackHeight - i, _item.getLocation());
+
 			if (_item.instruction() == Instruction::SSTORE)
 				op = storeInStorage(arguments[0], arguments[1], _item.getLocation());
 			else if (_item.instruction() == Instruction::SLOAD)
@@ -121,10 +122,16 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
 					applySha3(arguments.at(0), arguments.at(1), _item.getLocation())
 				);
 			else
+			{
+				if (SemanticInformation::invalidatesMemory(_item.instruction()))
+					resetMemory();
+				if (SemanticInformation::invalidatesStorage(_item.instruction()))
+					resetStorage();
 				setStackElement(
 					m_stackHeight + _item.deposit(),
 					m_expressionClasses->find(_item, arguments, _copyItem)
 				);
+			}
 		}
 		m_stackHeight += _item.deposit();
 	}
diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp
index 83d59efc7..40c36f9e3 100644
--- a/libevmasm/SemanticInformation.cpp
+++ b/libevmasm/SemanticInformation.cpp
@@ -122,3 +122,57 @@ bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
 		return false;
 	}
 }
+
+
+bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
+{
+	if (_item.type() != Operation)
+		return true;
+	assertThrow(!altersControlFlow(_item), OptimizerException, "");
+
+	switch (_item.instruction())
+	{
+	case Instruction::CALL:
+	case Instruction::CALLCODE:
+	case Instruction::CREATE:
+	case Instruction::GAS:
+	case Instruction::PC:
+	case Instruction::MSIZE: // depends on previous writes and reads, not only on content
+	case Instruction::BALANCE: // depends on previous calls
+	case Instruction::EXTCODESIZE:
+		return false;
+	default:
+		return true;
+	}
+}
+
+bool SemanticInformation::invalidatesMemory(Instruction _instruction)
+{
+	switch (_instruction)
+	{
+	case Instruction::CALLDATACOPY:
+	case Instruction::CODECOPY:
+	case Instruction::EXTCODECOPY:
+	case Instruction::MSTORE:
+	case Instruction::MSTORE8:
+	case Instruction::CALL:
+	case Instruction::CALLCODE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+bool SemanticInformation::invalidatesStorage(Instruction _instruction)
+{
+	switch (_instruction)
+	{
+	case Instruction::CALL:
+	case Instruction::CALLCODE:
+	case Instruction::CREATE:
+	case Instruction::SSTORE:
+		return true;
+	default:
+		return false;
+	}
+}
diff --git a/libevmasm/SemanticInformation.h b/libevmasm/SemanticInformation.h
index 27aa6f1a4..b14ddb65a 100644
--- a/libevmasm/SemanticInformation.h
+++ b/libevmasm/SemanticInformation.h
@@ -23,6 +23,7 @@
 
 #pragma once
 
+#include 
 
 namespace dev
 {
@@ -45,6 +46,14 @@ struct SemanticInformation
 	static bool isSwapInstruction(AssemblyItem const& _item);
 	static bool isJumpInstruction(AssemblyItem const& _item);
 	static bool altersControlFlow(AssemblyItem const& _item);
+	/// @returns false if the value put on the stack by _item depends on anything else than
+	/// the information in the current block header, memory, storage or stack.
+	/// @note should not be called for instructions that alter the control flow.
+	static bool isDeterministic(AssemblyItem const& _item);
+	/// @returns true if the given instruction modifies memory.
+	static bool invalidatesMemory(Instruction _instruction);
+	/// @returns true if the given instruction modifies storage (even indirectly).
+	static bool invalidatesStorage(Instruction _instruction);
 };
 
 }

From 1f149925bc6be94e4d07e887b3d7848f50b6cc0b Mon Sep 17 00:00:00 2001
From: chriseth 
Date: Mon, 4 May 2015 10:15:41 +0200
Subject: [PATCH 40/87] Gather knowledge about the state during control flow
 analysis.

---
 libevmasm/Assembly.cpp            |  7 ++-
 libevmasm/ControlFlowGraph.cpp    | 91 ++++++++++++++++++++++++++++++-
 libevmasm/ControlFlowGraph.h      | 22 ++++++--
 libevmasm/KnownState.cpp          | 75 +++++++++++++++++++------
 libevmasm/KnownState.h            | 30 +++++++---
 libevmasm/SemanticInformation.cpp |  1 -
 libevmasm/SemanticInformation.h   |  1 -
 7 files changed, 192 insertions(+), 35 deletions(-)

diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index c7253622e..1c5391168 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -314,6 +314,10 @@ Assembly& Assembly::optimise(bool _enable)
 		copt << toString(*this);
 		count = 0;
 
+		//@todo CFG interface should be a generator, that returns an item and a pointer to a
+		// knownstate, which has to replace the current state if it is not null.
+		// Feed these items to the CSE, but also store them and replace the stored version
+		// if the items generated by the CSE are shorter. (or even use less gas?)
 		copt << "Performing control flow analysis...";
 		{
 			ControlFlowGraph cfg(m_items);
@@ -329,7 +333,8 @@ Assembly& Assembly::optimise(bool _enable)
 		copt << "Performing common subexpression elimination...";
 		for (auto iter = m_items.begin(); iter != m_items.end();)
 		{
-			KnownState state;
+			//@todo use only a single state / expression classes instance.
+			KnownState state(make_shared());
 			CommonSubexpressionEliminator eliminator(state);
 			auto orig = iter;
 			iter = eliminator.feedItems(iter, m_items.end());
diff --git a/libevmasm/ControlFlowGraph.cpp b/libevmasm/ControlFlowGraph.cpp
index cc4367e64..0b0c757d6 100644
--- a/libevmasm/ControlFlowGraph.cpp
+++ b/libevmasm/ControlFlowGraph.cpp
@@ -23,9 +23,11 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
+#include 
 
 using namespace std;
 using namespace dev;
@@ -46,6 +48,7 @@ AssemblyItems ControlFlowGraph::optimisedItems()
 	resolveNextLinks();
 	removeUnusedBlocks();
 	setPrevLinks();
+	gatherKnowledge();
 
 	return rebuildCode();
 }
@@ -209,6 +212,77 @@ void ControlFlowGraph::setPrevLinks()
 	}
 }
 
+void ControlFlowGraph::gatherKnowledge()
+{
+	// @todo actually we know that memory is filled with zeros at the beginning,
+	// we could make use of that.
+	shared_ptr emptyState = make_shared();
+	ExpressionClasses& expr = emptyState->expressionClasses();
+	bool unknownJumpEncountered = false;
+
+	vector>> workQueue({make_pair(BlockId::initial(), emptyState->copy())});
+	while (!workQueue.empty())
+	{
+		//@todo we might have to do something like incrementing the sequence number for each JUMPDEST
+		assertThrow(!!workQueue.back().first, OptimizerException, "");
+		BasicBlock& block = m_blocks.at(workQueue.back().first);
+		shared_ptr state = workQueue.back().second;
+		workQueue.pop_back();
+		if (block.startState)
+		{
+			state->reduceToCommonKnowledge(*block.startState);
+			if (*state == *block.startState)
+				continue;
+		}
+
+		block.startState = state->copy();
+		//@todo we might know the return address for the first pass, but not anymore for the second,
+		// -> store knowledge about tags as a union.
+
+		// Feed all items except for the final jump yet because it will erase the target tag.
+		unsigned pc = block.begin;
+		while (pc < block.end && !SemanticInformation::altersControlFlow(m_items.at(pc)))
+			state->feedItem(m_items.at(pc++));
+
+		if (
+			block.endType == BasicBlock::EndType::JUMP ||
+			block.endType == BasicBlock::EndType::JUMPI
+		)
+		{
+			assertThrow(block.begin <= pc && pc == block.end - 1, OptimizerException, "");
+			//@todo in the case of JUMPI, add knowledge about the condition to the state
+			// (for both values of the condition)
+			BlockId nextBlock = expressionClassToBlockId(
+				state->stackElement(state->stackHeight(), SourceLocation()),
+				expr
+			);
+			state->feedItem(m_items.at(pc++));
+			if (nextBlock)
+				workQueue.push_back(make_pair(nextBlock, state->copy()));
+			else if (!unknownJumpEncountered)
+			{
+				// We do not know where this jump goes, so we have to reset the states of all
+				// JUMPDESTs.
+				unknownJumpEncountered = true;
+				for (auto const& it: m_blocks)
+					if (it.second.begin < it.second.end && m_items[it.second.begin].type() == Tag)
+						workQueue.push_back(make_pair(it.first, emptyState->copy()));
+			}
+		}
+		else if (block.begin <= pc && pc < block.end)
+			state->feedItem(m_items.at(pc++));
+		assertThrow(block.end <= block.begin || pc == block.end, OptimizerException, "");
+
+		block.endState = state;
+
+		if (
+			block.endType == BasicBlock::EndType::HANDOVER ||
+			block.endType == BasicBlock::EndType::JUMPI
+		)
+			workQueue.push_back(make_pair(block.next, state->copy()));
+	}
+}
+
 AssemblyItems ControlFlowGraph::rebuildCode()
 {
 	map pushes;
@@ -233,7 +307,7 @@ AssemblyItems ControlFlowGraph::rebuildCode()
 			blockId = m_blocks.at(blockId).prev;
 		for (; blockId; blockId = m_blocks.at(blockId).next)
 		{
-			BasicBlock const& block = m_blocks.at(blockId);
+			BasicBlock& block = m_blocks.at(blockId);
 			blocksToAdd.erase(blockId);
 			blocksAdded.insert(blockId);
 
@@ -243,7 +317,10 @@ AssemblyItems ControlFlowGraph::rebuildCode()
 				continue;
 			// If block starts with unused tag, skip it.
 			if (previousHandedOver && !pushes[blockId] && begin->type() == Tag)
+			{
 				++begin;
+				++block.begin;
+			}
 			previousHandedOver = (block.endType == BasicBlock::EndType::HANDOVER);
 			copy(begin, end, back_inserter(code));
 		}
@@ -252,6 +329,18 @@ AssemblyItems ControlFlowGraph::rebuildCode()
 	return code;
 }
 
+BlockId ControlFlowGraph::expressionClassToBlockId(
+	ExpressionClasses::Id _id,
+	ExpressionClasses& _exprClasses
+)
+{
+	ExpressionClasses::Expression expr = _exprClasses.representative(_id);
+	if (expr.item && expr.item->type() == PushTag)
+		return BlockId(expr.item->data());
+	else
+		return BlockId::invalid();
+}
+
 BlockId ControlFlowGraph::generateNewId()
 {
 	BlockId id = BlockId(++m_lastUsedId);
diff --git a/libevmasm/ControlFlowGraph.h b/libevmasm/ControlFlowGraph.h
index 5d16df327..4310d6642 100644
--- a/libevmasm/ControlFlowGraph.h
+++ b/libevmasm/ControlFlowGraph.h
@@ -24,16 +24,17 @@
 #pragma once
 
 #include 
+#include 
 #include 
 #include 
+#include 
 
 namespace dev
 {
 namespace eth
 {
 
-class AssemblyItem;
-using AssemblyItems = std::vector;
+class KnownState;
 
 /**
  * Identifier for a block, coincides with the tag number of an AssemblyItem but adds a special
@@ -69,14 +70,20 @@ struct BasicBlock
 	unsigned end = 0;
 	/// Tags pushed inside this block, with multiplicity.
 	std::vector pushedTags;
-	/// ID of the block that always follows this one (either JUMP or flow into new block),
-	/// or BlockId::invalid() otherwise
+	/// ID of the block that always follows this one (either non-branching part of JUMPI or flow
+	/// into new block), or BlockId::invalid() otherwise
 	BlockId next = BlockId::invalid();
-	/// ID of the block that has to precede this one.
+	/// ID of the block that has to precede this one (because control flows into it).
 	BlockId prev = BlockId::invalid();
 
 	enum class EndType { JUMP, JUMPI, STOP, HANDOVER };
 	EndType endType = EndType::HANDOVER;
+
+	/// Knowledge about the state when this block is entered. Intersection of all possible ways
+	/// to enter this block.
+	std::shared_ptr startState;
+	/// Knowledge about the state at the end of this block.
+	std::shared_ptr endState;
 };
 
 class ControlFlowGraph
@@ -93,9 +100,14 @@ private:
 	void splitBlocks();
 	void resolveNextLinks();
 	void removeUnusedBlocks();
+	void gatherKnowledge();
 	void setPrevLinks();
 	AssemblyItems rebuildCode();
 
+	/// @returns the corresponding BlockId if _id is a pushed jump tag,
+	/// and an invalid BlockId otherwise.
+	BlockId expressionClassToBlockId(ExpressionClasses::Id _id, ExpressionClasses& _exprClasses);
+
 	BlockId generateNewId();
 
 	unsigned m_lastUsedId = 0;
diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp
index 632777c82..7ff0143e1 100644
--- a/libevmasm/KnownState.cpp
+++ b/libevmasm/KnownState.cpp
@@ -30,16 +30,18 @@ using namespace std;
 using namespace dev;
 using namespace dev::eth;
 
-ostream& KnownState::stream(
-	ostream& _out,
-	map _initialStack,
-	map _targetStack
-) const
+ostream& KnownState::stream(ostream& _out) const
 {
 	auto streamExpressionClass = [this](ostream& _out, Id _id)
 	{
 		auto const& expr = m_expressionClasses->representative(_id);
-		_out << "  " << dec << _id << ": " << *expr.item;
+		_out << "  " << dec << _id << ": ";
+		if (!expr.item)
+			_out << " no item";
+		else if (expr.item->type() == UndefinedItem)
+			_out << " unknown " << int(expr.item->data());
+		else
+			_out << *expr.item;
 		if (expr.sequenceNumber)
 			_out << "@" << dec << expr.sequenceNumber;
 		_out << "(";
@@ -48,22 +50,32 @@ ostream& KnownState::stream(
 		_out << ")" << endl;
 	};
 
-	_out << "Optimizer analysis:" << endl;
-	_out << "Final stack height: " << dec << m_stackHeight << endl;
+	_out << "=== State ===" << endl;
+	_out << "Stack height: " << dec << m_stackHeight << endl;
 	_out << "Equivalence classes: " << endl;
 	for (Id eqClass = 0; eqClass < m_expressionClasses->size(); ++eqClass)
 		streamExpressionClass(_out, eqClass);
 
-	_out << "Initial stack: " << endl;
-	for (auto const& it: _initialStack)
+	_out << "Stack: " << endl;
+	for (auto const& it: m_stackElements)
 	{
 		_out << "  " << dec << it.first << ": ";
 		streamExpressionClass(_out, it.second);
 	}
-	_out << "Target stack: " << endl;
-	for (auto const& it: _targetStack)
+	_out << "Storage: " << endl;
+	for (auto const& it: m_storageContent)
 	{
-		_out << "  " << dec << it.first << ": ";
+		_out << "  ";
+		streamExpressionClass(_out, it.first);
+		_out << ": ";
+		streamExpressionClass(_out, it.second);
+	}
+	_out << "Memory: " << endl;
+	for (auto const& it: m_memoryContent)
+	{
+		_out << "  ";
+		streamExpressionClass(_out, it.first);
+		_out << ": ";
 		streamExpressionClass(_out, it.second);
 	}
 
@@ -73,7 +85,11 @@ ostream& KnownState::stream(
 KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool _copyItem)
 {
 	StoreOperation op;
-	if (_item.type() != Operation)
+	if (_item.type() == Tag)
+	{
+		// can be ignored
+	}
+	else if (_item.type() != Operation)
 	{
 		assertThrow(_item.deposit() == 1, InvalidDeposit, "");
 		setStackElement(++m_stackHeight, m_expressionClasses->find(_item, {}, _copyItem));
@@ -127,17 +143,40 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
 					resetMemory();
 				if (SemanticInformation::invalidatesStorage(_item.instruction()))
 					resetStorage();
-				setStackElement(
-					m_stackHeight + _item.deposit(),
-					m_expressionClasses->find(_item, arguments, _copyItem)
-				);
+				assertThrow(info.ret <= 1, InvalidDeposit, "");
+				if (info.ret == 1)
+					setStackElement(
+						m_stackHeight + _item.deposit(),
+						m_expressionClasses->find(_item, arguments, _copyItem)
+					);
 			}
 		}
+		for (int p = m_stackHeight; p > m_stackHeight + _item.deposit(); --p)
+			m_stackElements.erase(p);
 		m_stackHeight += _item.deposit();
 	}
 	return op;
 }
 
+void KnownState::reduceToCommonKnowledge(KnownState const& /*_other*/)
+{
+	//@todo
+	*this = KnownState(m_expressionClasses);
+}
+
+bool KnownState::operator==(const KnownState& _other) const
+{
+	//@todo
+	return (
+		m_stackElements.empty() &&
+		_other.m_stackElements.empty() &&
+		m_storageContent.empty() &&
+		_other.m_storageContent.empty() &&
+		m_memoryContent.empty() &&
+		_other.m_memoryContent.empty()
+	);
+}
+
 ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation const& _location)
 {
 	if (m_stackElements.count(_stackHeight))
diff --git a/libevmasm/KnownState.h b/libevmasm/KnownState.h
index c6dfcee6b..f7a3dd675 100644
--- a/libevmasm/KnownState.h
+++ b/libevmasm/KnownState.h
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -70,14 +71,14 @@ public:
 		Id expression;
 	};
 
-	KnownState(): m_expressionClasses(std::make_shared()) {}
+	explicit KnownState(
+		std::shared_ptr _expressionClasses = std::make_shared()
+	): m_expressionClasses(_expressionClasses)
+	{
+	}
 
 	/// Streams debugging information to @a _out.
-	std::ostream& stream(
-		std::ostream& _out,
-		std::map _initialStack = std::map(),
-		std::map _targetStack = std::map()
-	) const;
+	std::ostream& stream(std::ostream& _out) const;
 
 	/// Feeds the item into the system for analysis.
 	/// @returns a possible store operation
@@ -92,6 +93,20 @@ public:
 	/// Resets any knowledge.
 	void reset() { resetStorage(); resetMemory(); resetStack(); }
 
+	/// Manually increments the storage and memory sequence number.
+	void incrementSequenceNumber() { m_sequenceNumber += 2; }
+
+	/// Replaces the state by the intersection with _other, i.e. only equal knowledge is retained.
+	/// If the stack heighht is different, the smaller one is used and the stack is compared
+	/// relatively.
+	void reduceToCommonKnowledge(KnownState const& _other);
+
+	/// @returns a shared pointer to a copy of this state.
+	std::shared_ptr copy() const { return std::make_shared(*this); }
+
+	/// @returns true if the knowledge about the state of both objects is (known to be) equal.
+	bool operator==(KnownState const& _other) const;
+
 	///@todo the sequence numbers in two copies of this class should never be the same.
 	/// might be doable using two-dimensional sequence numbers, where the first value is incremented
 	/// for each copy
@@ -99,8 +114,7 @@ public:
 	/// Retrieves the current equivalence class fo the given stack element (or generates a new
 	/// one if it does not exist yet).
 	Id stackElement(int _stackHeight, SourceLocation const& _location);
-	/// @returns the equivalence class id of the special initial stack element at the given height
-	/// (must not be positive).
+	/// @returns the equivalence class id of the special initial stack element at the given height.
 	Id initialStackElement(int _stackHeight, SourceLocation const& _location);
 
 	int stackHeight() const { return m_stackHeight; }
diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp
index 40c36f9e3..056162b5f 100644
--- a/libevmasm/SemanticInformation.cpp
+++ b/libevmasm/SemanticInformation.cpp
@@ -128,7 +128,6 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
 {
 	if (_item.type() != Operation)
 		return true;
-	assertThrow(!altersControlFlow(_item), OptimizerException, "");
 
 	switch (_item.instruction())
 	{
diff --git a/libevmasm/SemanticInformation.h b/libevmasm/SemanticInformation.h
index b14ddb65a..094f45912 100644
--- a/libevmasm/SemanticInformation.h
+++ b/libevmasm/SemanticInformation.h
@@ -48,7 +48,6 @@ struct SemanticInformation
 	static bool altersControlFlow(AssemblyItem const& _item);
 	/// @returns false if the value put on the stack by _item depends on anything else than
 	/// the information in the current block header, memory, storage or stack.
-	/// @note should not be called for instructions that alter the control flow.
 	static bool isDeterministic(AssemblyItem const& _item);
 	/// @returns true if the given instruction modifies memory.
 	static bool invalidatesMemory(Instruction _instruction);

From ec7425fecde40ccf38bd5cd6d348c840e480ee25 Mon Sep 17 00:00:00 2001
From: chriseth 
Date: Tue, 5 May 2015 17:03:07 +0200
Subject: [PATCH 41/87] Remove unused old optimizer rule.

---
 libevmasm/Assembly.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index 1c5391168..aec06aef6 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -304,9 +304,6 @@ Assembly& Assembly::optimise(bool _enable)
 {
 	if (!_enable)
 		return *this;
-	std::vector>> rules;
-	// jump to next instruction
-	rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data() == m[2].data()) return {m[2]}; else return m.toVector(); }});
 
 	unsigned total = 0;
 	for (unsigned count = 1; count > 0; total += count)

From 1933aa5c2cb41300001daad91779591d7aa0b970 Mon Sep 17 00:00:00 2001
From: chriseth 
Date: Tue, 5 May 2015 17:45:58 +0200
Subject: [PATCH 42/87] CFG returns vector of blocks instead of assembly items.

---
 libevmasm/Assembly.cpp                 |  5 ++++-
 libevmasm/ControlFlowGraph.cpp         | 28 +++++++++++---------------
 libevmasm/ControlFlowGraph.h           | 14 ++++++++-----
 test/libsolidity/SolidityOptimizer.cpp |  8 ++++++--
 4 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index aec06aef6..9530ded49 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -318,7 +318,10 @@ Assembly& Assembly::optimise(bool _enable)
 		copt << "Performing control flow analysis...";
 		{
 			ControlFlowGraph cfg(m_items);
-			AssemblyItems optItems = cfg.optimisedItems();
+			AssemblyItems optItems;
+			for (BasicBlock const& block: cfg.optimisedBlocks())
+				copy(m_items.begin() + block.begin, m_items.begin() + block.end,
+					 back_inserter(optItems));
 			if (optItems.size() < m_items.size())
 			{
 				copt << "Old size: " << m_items.size() << ", new size: " << optItems.size();
diff --git a/libevmasm/ControlFlowGraph.cpp b/libevmasm/ControlFlowGraph.cpp
index 0b0c757d6..2e28317a3 100644
--- a/libevmasm/ControlFlowGraph.cpp
+++ b/libevmasm/ControlFlowGraph.cpp
@@ -38,10 +38,10 @@ BlockId::BlockId(u256 const& _id): m_id(_id)
 	assertThrow( _id < initial().m_id, OptimizerException, "Tag number too large.");
 }
 
-AssemblyItems ControlFlowGraph::optimisedItems()
+BasicBlocks ControlFlowGraph::optimisedBlocks()
 {
 	if (m_items.empty())
-		return m_items;
+		return BasicBlocks();
 
 	findLargestTag();
 	splitBlocks();
@@ -216,17 +216,17 @@ void ControlFlowGraph::gatherKnowledge()
 {
 	// @todo actually we know that memory is filled with zeros at the beginning,
 	// we could make use of that.
-	shared_ptr emptyState = make_shared();
+	KnownStatePointer emptyState = make_shared();
 	ExpressionClasses& expr = emptyState->expressionClasses();
 	bool unknownJumpEncountered = false;
 
-	vector>> workQueue({make_pair(BlockId::initial(), emptyState->copy())});
+	vector> workQueue({make_pair(BlockId::initial(), emptyState->copy())});
 	while (!workQueue.empty())
 	{
 		//@todo we might have to do something like incrementing the sequence number for each JUMPDEST
 		assertThrow(!!workQueue.back().first, OptimizerException, "");
 		BasicBlock& block = m_blocks.at(workQueue.back().first);
-		shared_ptr state = workQueue.back().second;
+		KnownStatePointer state = workQueue.back().second;
 		workQueue.pop_back();
 		if (block.startState)
 		{
@@ -283,7 +283,7 @@ void ControlFlowGraph::gatherKnowledge()
 	}
 }
 
-AssemblyItems ControlFlowGraph::rebuildCode()
+BasicBlocks ControlFlowGraph::rebuildCode()
 {
 	map pushes;
 	for (auto& idAndBlock: m_blocks)
@@ -294,7 +294,7 @@ AssemblyItems ControlFlowGraph::rebuildCode()
 	for (auto it: m_blocks)
 		blocksToAdd.insert(it.first);
 	set blocksAdded;
-	AssemblyItems code;
+	BasicBlocks blocks;
 
 	for (
 		BlockId blockId = BlockId::initial();
@@ -311,22 +311,18 @@ AssemblyItems ControlFlowGraph::rebuildCode()
 			blocksToAdd.erase(blockId);
 			blocksAdded.insert(blockId);
 
-			auto begin = m_items.begin() + block.begin;
-			auto end = m_items.begin() + block.end;
-			if (begin == end)
+			if (block.begin == block.end)
 				continue;
 			// If block starts with unused tag, skip it.
-			if (previousHandedOver && !pushes[blockId] && begin->type() == Tag)
-			{
-				++begin;
+			if (previousHandedOver && !pushes[blockId] && m_items[block.begin].type() == Tag)
 				++block.begin;
-			}
+			if (block.begin < block.end)
+				blocks.push_back(block);
 			previousHandedOver = (block.endType == BasicBlock::EndType::HANDOVER);
-			copy(begin, end, back_inserter(code));
 		}
 	}
 
-	return code;
+	return blocks;
 }
 
 BlockId ControlFlowGraph::expressionClassToBlockId(
diff --git a/libevmasm/ControlFlowGraph.h b/libevmasm/ControlFlowGraph.h
index 4310d6642..3366dc45f 100644
--- a/libevmasm/ControlFlowGraph.h
+++ b/libevmasm/ControlFlowGraph.h
@@ -35,6 +35,7 @@ namespace eth
 {
 
 class KnownState;
+using KnownStatePointer = std::shared_ptr;
 
 /**
  * Identifier for a block, coincides with the tag number of an AssemblyItem but adds a special
@@ -81,19 +82,22 @@ struct BasicBlock
 
 	/// Knowledge about the state when this block is entered. Intersection of all possible ways
 	/// to enter this block.
-	std::shared_ptr startState;
+	KnownStatePointer startState;
 	/// Knowledge about the state at the end of this block.
-	std::shared_ptr endState;
+	KnownStatePointer endState;
 };
 
+using BasicBlocks = std::vector;
+
 class ControlFlowGraph
 {
 public:
 	/// Initializes the control flow graph.
 	/// @a _items has to persist across the usage of this class.
 	ControlFlowGraph(AssemblyItems const& _items): m_items(_items) {}
-	/// @returns the collection of optimised items, should be called only once.
-	AssemblyItems optimisedItems();
+	/// @returns vector of basic blocks in the order they should be used in the final code.
+	/// Should be called only once.
+	BasicBlocks optimisedBlocks();
 
 private:
 	void findLargestTag();
@@ -102,7 +106,7 @@ private:
 	void removeUnusedBlocks();
 	void gatherKnowledge();
 	void setPrevLinks();
-	AssemblyItems rebuildCode();
+	BasicBlocks rebuildCode();
 
 	/// @returns the corresponding BlockId if _id is a pushed jump tag,
 	/// and an invalid BlockId otherwise.
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index 59e8f04a8..3cb6a536a 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -131,8 +131,12 @@ public:
 		// Running it four times should be enough for these tests.
 		for (unsigned i = 0; i < 4; ++i)
 		{
-			eth::ControlFlowGraph cfg(output);
-			output = cfg.optimisedItems();
+			ControlFlowGraph cfg(output);
+			AssemblyItems optItems;
+			for (BasicBlock const& block: cfg.optimisedBlocks())
+				copy(output.begin() + block.begin, output.begin() + block.end,
+					 back_inserter(optItems));
+			output = move(optItems);
 		}
 		BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
 	}

From df02fc61e3c30c8f5ce94803af204dfd5346e662 Mon Sep 17 00:00:00 2001
From: Marek Kotewicz 
Date: Wed, 6 May 2015 20:46:15 +0200
Subject: [PATCH 43/87] style fixes

---
 eth/main.cpp                   |  2 +-
 libjsconsole/CMakeLists.txt    |  5 +----
 libjsconsole/JSConsole.cpp     |  4 ++--
 libjsconsole/JSResources.cmake |  7 -------
 libjsconsole/JSV8Connector.cpp |  4 ++--
 libjsconsole/JSV8Connector.h   | 10 ++++++----
 libjsengine/JSEngine.h         |  1 +
 libjsengine/JSPrinter.h        |  1 -
 libjsengine/JSV8Engine.cpp     | 26 +++++++++++++-------------
 libjsengine/JSV8Engine.h       |  6 +++---
 libjsengine/JSV8Printer.h      |  2 +-
 libjsengine/JSV8RPC.cpp        |  8 ++++----
 libjsengine/JSV8RPC.h          |  6 +++---
 13 files changed, 37 insertions(+), 45 deletions(-)
 delete mode 100644 libjsconsole/JSResources.cmake

diff --git a/eth/main.cpp b/eth/main.cpp
index f333ce2d6..a5624b69b 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -411,7 +411,7 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
 	exit(0);
 }
 
-void stopMiningAfterXBlocks(eth::Client *_c, unsigned _start, unsigned _mining)
+void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned _mining)
 {
 	if (_c->isMining() && _c->blockChain().details().number - _start == _mining)
 		_c->stopMining();
diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt
index f54b7a1c7..e8f98de88 100644
--- a/libjsconsole/CMakeLists.txt
+++ b/libjsconsole/CMakeLists.txt
@@ -19,10 +19,7 @@ set(EXECUTABLE jsconsole)
 
 file(GLOB HEADERS "*.h")
 
-include(EthUtils)
-eth_add_resources("${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake" JSRES)
-
-add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES})
+add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
 
 target_link_libraries(${EXECUTABLE} jsengine)
 target_link_libraries(${EXECUTABLE} devcore)
diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp
index 15fbb1671..791df2de4 100644
--- a/libjsconsole/JSConsole.cpp
+++ b/libjsconsole/JSConsole.cpp
@@ -36,8 +36,8 @@ using namespace dev;
 using namespace dev::eth;
 
 JSConsole::JSConsole(WebThreeDirect& _web3, std::vector const& _accounts):
-		m_engine(),
-		m_printer(m_engine)
+	m_engine(),
+	m_printer(m_engine)
 {
 	m_jsonrpcConnector.reset(new JSV8Connector(m_engine));
 	m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts));
diff --git a/libjsconsole/JSResources.cmake b/libjsconsole/JSResources.cmake
deleted file mode 100644
index 889dd2f2b..000000000
--- a/libjsconsole/JSResources.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-
-set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js")
-
-set(ETH_RESOURCE_NAME "JSConsoleResources")
-set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}")
-set(ETH_RESOURCES "web3")
-
diff --git a/libjsconsole/JSV8Connector.cpp b/libjsconsole/JSV8Connector.cpp
index 21295bec0..ed560a368 100644
--- a/libjsconsole/JSV8Connector.cpp
+++ b/libjsconsole/JSV8Connector.cpp
@@ -36,14 +36,14 @@ bool JSV8Connector::StopListening()
 	return true;
 }
 
-bool JSV8Connector::SendResponse(std::string const &_response, void *_addInfo)
+bool JSV8Connector::SendResponse(std::string const& _response, void* _addInfo)
 {
 	(void)_addInfo;
 	m_lastResponse = _response.c_str();
 	return true;
 }
 
-void JSV8Connector::onSend(const char *payload)
+void JSV8Connector::onSend(char const* payload)
 {
 	OnRequest(payload, NULL);
 }
diff --git a/libjsconsole/JSV8Connector.h b/libjsconsole/JSV8Connector.h
index 5ad9c177c..98cef4c2c 100644
--- a/libjsconsole/JSV8Connector.h
+++ b/libjsconsole/JSV8Connector.h
@@ -30,18 +30,20 @@ namespace dev
 namespace eth
 {
 
-class JSV8Connector : public jsonrpc::AbstractServerConnector, public JSV8RPC
+class JSV8Connector: public jsonrpc::AbstractServerConnector, public JSV8RPC
 {
 
 public:
-	JSV8Connector(JSV8Engine const &_engine) : JSV8RPC(_engine) {}
+	JSV8Connector(JSV8Engine const& _engine): JSV8RPC(_engine) {}
 	virtual ~JSV8Connector();
 
+	// implement AbstractServerConnector interface
 	bool StartListening();
 	bool StopListening();
-	bool SendResponse(std::string const& _response, void* _addInfo = NULL);
+	bool SendResponse(std::string const& _response, void* _addInfo = nullptr);
 
-	void onSend(const char* payload);
+	// implement JSV8RPC interface
+	void onSend(char const* payload);
 };
 
 }
diff --git a/libjsengine/JSEngine.h b/libjsengine/JSEngine.h
index 78937a536..ce54379a1 100644
--- a/libjsengine/JSEngine.h
+++ b/libjsengine/JSEngine.h
@@ -37,6 +37,7 @@ public:
 	JSString(char const* _cstr);
 	~JSString();
 	char const* cstr() const { return m_cstr; }
+
 private:
 	char* m_cstr;
 };
diff --git a/libjsengine/JSPrinter.h b/libjsengine/JSPrinter.h
index d5f84d2d3..bf13fcea7 100644
--- a/libjsengine/JSPrinter.h
+++ b/libjsengine/JSPrinter.h
@@ -39,4 +39,3 @@ public:
 
 }
 }
-
diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp
index 437bcb6a4..4e06f0f65 100644
--- a/libjsengine/JSV8Engine.cpp
+++ b/libjsengine/JSV8Engine.cpp
@@ -42,29 +42,29 @@ static char const* toCString(v8::String::Utf8Value const& _value)
 
 // from:        https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
 // v3.15 from:  https://chromium.googlesource.com/v8/v8.git/+/3.14.5.9/samples/shell.cc
-void reportException(v8::TryCatch*_try_catch)
+void reportException(v8::TryCatch* _tryCatch)
 {
 	v8::HandleScope handle_scope;
-	v8::String::Utf8Value exception(_try_catch->Exception());
-	char const* exception_string = toCString(exception);
-	v8::Handle message = _try_catch->Message();
+	v8::String::Utf8Value exception(_tryCatch->Exception());
+	char const* exceptionString = toCString(exception);
+	v8::Handle message = _tryCatch->Message();
 
 	// V8 didn't provide any extra information about this error; just
 	// print the exception.
 	if (message.IsEmpty())
-		printf("%s\n", exception_string);
+		printf("%s\n", exceptionString);
 	else
 	{
 		// Print (filename):(line number): (message).
 		v8::String::Utf8Value filename(message->GetScriptResourceName());
-		char const* filename_string = toCString(filename);
+		char const* filenameString = toCString(filename);
 		int linenum = message->GetLineNumber();
-		printf("%s:%i: %s\n", filename_string, linenum, exception_string);
+		printf("%s:%i: %s\n", filenameString, linenum, exceptionString);
 
 		// Print line of source code.
 		v8::String::Utf8Value sourceline(message->GetSourceLine());
-		char const* sourceline_string = toCString(sourceline);
-		printf("%s\n", sourceline_string);
+		char const* sourcelineString = toCString(sourceline);
+		printf("%s\n", sourcelineString);
 
 		// Print wavy underline (GetUnderline is deprecated).
 		int start = message->GetStartColumn();
@@ -78,11 +78,11 @@ void reportException(v8::TryCatch*_try_catch)
 
 		printf("\n");
 
-		v8::String::Utf8Value stack_trace(_try_catch->StackTrace());
-		if (stack_trace.length() > 0)
+		v8::String::Utf8Value stackTrace(_tryCatch->StackTrace());
+		if (stackTrace.length() > 0)
 		{
-			char const* stack_trace_string = toCString(stack_trace);
-			printf("%s\n", stack_trace_string);
+			char const* stackTraceString = toCString(stackTrace);
+			printf("%s\n", stackTraceString);
 		}
 	}
 }
diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h
index d785a71ba..56459c5d0 100644
--- a/libjsengine/JSV8Engine.h
+++ b/libjsengine/JSV8Engine.h
@@ -33,18 +33,18 @@ namespace eth
 class JSV8Env;
 class JSV8Scope;
 
-class JSV8Value : public JSValue
+class JSV8Value: public JSValue
 {
 public:
 	JSV8Value(v8::Handle _value): m_value(_value) {}
 	JSString toString() const;
-
 	v8::Handle const& value() const { return m_value; }
+
 private:
 	v8::Handle m_value;
 };
 
-class JSV8Engine : public JSEngine
+class JSV8Engine: public JSEngine
 {
 public:
 	JSV8Engine();
diff --git a/libjsengine/JSV8Printer.h b/libjsengine/JSV8Printer.h
index 0d9d06e0d..2ec9c78b6 100644
--- a/libjsengine/JSV8Printer.h
+++ b/libjsengine/JSV8Printer.h
@@ -30,7 +30,7 @@ namespace dev
 namespace eth
 {
 
-class JSV8Printer : public JSPrinter
+class JSV8Printer: public JSPrinter
 {
 public:
 	JSV8Printer(JSV8Engine const& _engine);
diff --git a/libjsengine/JSV8RPC.cpp b/libjsengine/JSV8RPC.cpp
index e75bfeada..994cfbbf2 100644
--- a/libjsengine/JSV8RPC.cpp
+++ b/libjsengine/JSV8RPC.cpp
@@ -30,7 +30,7 @@ namespace dev
 namespace eth
 {
 
-v8::Handle JSV8RPCSend(v8::Arguments const& args)
+v8::Handle JSV8RPCSend(v8::Arguments const& _args)
 {
 	v8::Local JSON = v8::String::New("JSON");
 	v8::Local parse = v8::String::New("parse");
@@ -39,10 +39,10 @@ v8::Handle JSV8RPCSend(v8::Arguments const& args)
 	v8::Handle parseFunc = v8::Handle::Cast(jsonObject->Get(parse));
 	v8::Handle stringifyFunc = v8::Handle::Cast(jsonObject->Get(stringify));
 
-	v8::Local self = args.Holder();
+	v8::Local self = _args.Holder();
 	v8::Local wrap = v8::Local::Cast(self->GetInternalField(0));
 	JSV8RPC* that = static_cast(wrap->Value());
-	v8::Local vals[1] = {args[0]->ToObject()};
+	v8::Local vals[1] = {_args[0]->ToObject()};
 	v8::Local stringifiedArg = stringifyFunc->Call(stringifyFunc, 1, vals);
 	v8::String::Utf8Value str(stringifiedArg);
 	that->onSend(*str);
@@ -54,7 +54,7 @@ v8::Handle JSV8RPCSend(v8::Arguments const& args)
 }
 }
 
-JSV8RPC::JSV8RPC(JSV8Engine const &_engine): m_engine(_engine)
+JSV8RPC::JSV8RPC(JSV8Engine const& _engine): m_engine(_engine)
 {
 	v8::HandleScope scope;
 	v8::Local rpcTemplate = v8::ObjectTemplate::New();
diff --git a/libjsengine/JSV8RPC.h b/libjsengine/JSV8RPC.h
index 7dfb42392..a2180ef51 100644
--- a/libjsengine/JSV8RPC.h
+++ b/libjsengine/JSV8RPC.h
@@ -33,14 +33,14 @@ class JSV8RPC
 {
 public:
 	JSV8RPC(JSV8Engine const& _engine);
-	virtual void onSend(const char* _payload) = 0;
-	const char* lastResponse() const { return m_lastResponse; }
+	virtual void onSend(char const* _payload) = 0;
+	char const* lastResponse() const { return m_lastResponse; }
 
 private:
 	JSV8Engine const& m_engine;
 
 protected:
-	const char* m_lastResponse;
+	char const* m_lastResponse;
 };
 
 }

From cc5a617aa68cee9abc2ba913491bb96e79c7a8af Mon Sep 17 00:00:00 2001
From: arkpar 
Date: Thu, 7 May 2015 09:51:06 +0200
Subject: [PATCH 44/87] set and map to hash tables

---
 alethzero/Debugger.h                      |  2 +-
 alethzero/ExportState.cpp                 | 12 ++++--
 alethzero/MainWin.cpp                     |  2 +-
 cmake/EthCompilerSettings.cmake           |  1 +
 libdevcore/Common.h                       | 17 ++++++++
 libdevcore/CommonData.h                   |  8 ++++
 libdevcore/FixedHash.h                    | 48 ++++++++++++++++++-----
 libdevcore/Log.h                          | 24 ++++++++++++
 libdevcore/RLP.h                          |  1 +
 libdevcrypto/Common.h                     |  4 +-
 libdevcrypto/MemoryDB.cpp                 |  8 ++--
 libdevcrypto/MemoryDB.h                   | 10 ++---
 libdevcrypto/TrieDB.h                     | 13 +++---
 libethcore/EthashAux.h                    |  6 +--
 libethereum/Account.h                     |  6 +--
 libethereum/AccountDiff.h                 |  2 +-
 libethereum/BlockChain.cpp                |  4 +-
 libethereum/BlockChain.h                  |  4 +-
 libethereum/BlockQueue.h                  | 18 ++++-----
 libethereum/CachedAddressState.cpp        |  4 +-
 libethereum/CachedAddressState.h          |  2 +-
 libethereum/CanonBlockChain.cpp           |  4 +-
 libethereum/CanonBlockChain.h             |  2 +-
 libethereum/Client.cpp                    | 12 +++---
 libethereum/Client.h                      |  6 +--
 libethereum/ClientBase.cpp                |  2 +-
 libethereum/ClientBase.h                  |  8 ++--
 libethereum/DownloadMan.cpp               |  4 +-
 libethereum/DownloadMan.h                 | 12 +++---
 libethereum/EthereumHost.cpp              |  3 +-
 libethereum/EthereumHost.h                | 10 ++---
 libethereum/EthereumPeer.h                |  5 +--
 libethereum/ExtVM.h                       |  4 +-
 libethereum/Interface.h                   |  4 +-
 libethereum/LogFilter.h                   |  4 +-
 libethereum/Precompiled.cpp               |  4 +-
 libethereum/Precompiled.h                 |  4 +-
 libethereum/State.cpp                     | 22 +++++------
 libethereum/State.h                       | 17 ++++----
 libethereum/TransactionQueue.h            | 18 ++++-----
 libethereum/TransactionReceipt.h          |  1 -
 libp2p/Common.h                           | 23 +++++++++++
 libp2p/Host.h                             |  4 +-
 libp2p/Network.cpp                        |  2 +-
 libp2p/NodeTable.cpp                      | 17 ++++----
 libp2p/NodeTable.h                        | 36 ++++++++---------
 mix/ClientModel.cpp                       |  6 +--
 mix/ClientModel.h                         |  4 +-
 mix/MachineStates.h                       |  2 +-
 mix/MixClient.cpp                         |  4 +-
 mix/MixClient.h                           |  2 +-
 test/TestHelper.cpp                       |  2 +-
 test/fuzzTesting/checkRandomStateTest.cpp |  2 +-
 test/libethereum/state.cpp                |  2 +-
 54 files changed, 275 insertions(+), 173 deletions(-)

diff --git a/alethzero/Debugger.h b/alethzero/Debugger.h
index 76ef6a0d3..38ed973df 100644
--- a/alethzero/Debugger.h
+++ b/alethzero/Debugger.h
@@ -45,7 +45,7 @@ struct WorldState
 	dev::u256s stack;
 	dev::bytes memory;
 	dev::bigint gasCost;
-	std::map storage;
+	std::unordered_map storage;
 	std::vector levels;
 };
 
diff --git a/alethzero/ExportState.cpp b/alethzero/ExportState.cpp
index a8e47ad6a..c11132768 100644
--- a/alethzero/ExportState.cpp
+++ b/alethzero/ExportState.cpp
@@ -91,7 +91,7 @@ void ExportStateDialog::fillBlocks()
 	while (i > 0 && i >= m_recentBlocks)
 		ui->block->removeItem(i--);
 
-	h256Set blocks;
+	h256Hash blocks;
 	for (QString f: filters)
 	{
 		if (f.startsWith("#"))
@@ -153,13 +153,17 @@ void ExportStateDialog::generateJSON()
 		auto address = Address((byte const*)hba.data(), Address::ConstructFromPointer);
 		json << prefix << "\t\"" << toHex(address.ref()) << "\":\n\t{\n\t\t\"wei\": \"" << ethereum()->balanceAt(address, m_block) << "\",\n";
 		json << "\t\t\"code\": \"" << toHex(ethereum()->codeAt(address, m_block)) << "\",\n";
-		std::map storage = ethereum()->storageAt(address, m_block);
+		std::unordered_map storage = ethereum()->storageAt(address, m_block);
 		if (!storage.empty())
 		{
 			json << "\t\t\"storage\":\n\t\t{\n";
+			std::string storagePrefix;
 			for (auto s: storage)
-				json << "\t\t\t\"" << toHex(s.first) << "\": \"" << toHex(s.second) << "\"" << (s.first == storage.rbegin()->first ? "" : ",") <<"\n";
-			json << "\t\t}\n";
+			{
+				json << storagePrefix << "\t\t\t\"" << toHex(s.first) << "\": \"" << toHex(s.second) << "\"";
+				storagePrefix = ",\n";
+			}
+			json << "\n\t\t}\n";
 		}
 		json << "\t}";
 		prefix = ",\n";
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index e5504cab2..437e75576 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -1092,7 +1092,7 @@ void Main::refreshBlockChain()
 	auto const& bc = ethereum()->blockChain();
 	QStringList filters = ui->blockChainFilter->text().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
 
-	h256Set blocks;
+	h256Hash blocks;
 	for (QString f: filters)
 		if (f.size() == 64)
 		{
diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake
index 9e9ae687e..0d6fd7907 100644
--- a/cmake/EthCompilerSettings.cmake
+++ b/cmake/EthCompilerSettings.cmake
@@ -55,6 +55,7 @@ endif ()
 
 if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")))
 	set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")
+	set(CMAKE_C_FLAGS "-g ${CMAKE_C_FLAGS}")
 	add_definitions(-DETH_PROFILING_GPERF)
 	set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lprofiler")
 #	set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -lprofiler")
diff --git a/libdevcore/Common.h b/libdevcore/Common.h
index e0872b5d4..36e57c44f 100644
--- a/libdevcore/Common.h
+++ b/libdevcore/Common.h
@@ -34,10 +34,13 @@
 #endif
 
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
+#include 
 #pragma warning(push)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
@@ -84,6 +87,10 @@ using StringMap = std::map;
 using u256Map = std::map;
 using HexMap = std::map;
 
+// Hash types.
+using StringHashMap = std::unordered_map;
+using u256HashMap = std::unordered_map;
+
 // String types.
 using strings = std::vector;
 
@@ -215,4 +222,14 @@ inline dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
 	return static_cast(max(static_cast(_a), static_cast(_b)));
 }
 
+template <> struct hash
+{
+	size_t operator()(dev::u256 const& _a) const
+	{
+		unsigned size = _a.backend().size();
+		auto limbs = _a.backend().limbs();
+		return boost::hash_range(limbs, limbs + size);
+	}
+};
+
 }
diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h
index a0ea01a1b..6c1f34667 100644
--- a/libdevcore/CommonData.h
+++ b/libdevcore/CommonData.h
@@ -258,6 +258,14 @@ template  std::set& operator+=(std::set& _a, U const& _b
 	return _a;
 }
 
+/// Insert the contents of a container into an unordered_st
+template  std::unordered_set& operator+=(std::unordered_set& _a, U const& _b)
+{
+	for (auto const& i: _b)
+		_a.insert(i);
+	return _a;
+}
+
 /// Concatenate the contents of a container onto a vector
 template  std::vector& operator+=(std::vector& _a, U const& _b)
 {
diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h
index 2cf81cb77..5ba96b9a8 100644
--- a/libdevcore/FixedHash.h
+++ b/libdevcore/FixedHash.h
@@ -147,17 +147,10 @@ public:
 	/// @returns a random valued object.
 	static FixedHash random() { return random(s_fixedHashEngine); }
 
-	/// A generic std::hash compatible function object.
 	struct hash
 	{
 		/// Make a hash of the object's data.
-		size_t operator()(FixedHash const& value) const
-		{
-			size_t h = 0;
-			for (auto i: value.m_data)
-				h = (h << (5 - h)) + i;
-			return h;
-		}
+		size_t operator()(FixedHash const& value) const;
 	};
 
 	template  inline FixedHash& shiftBloom(FixedHash const& _h)
@@ -215,6 +208,23 @@ template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) co
 	return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]);
 }
 
+/// Fast std::hash compatible hash function object for h64.
+template<> inline size_t FixedHash<8>::hash::operator()(FixedHash<8> const& value) const
+{
+	const uint64_t*data = (const uint64_t*)value.data();
+	return (size_t)(*data);
+}
+
+/// Fast std::hash compatible hash function object for h160.
+template<> inline size_t FixedHash<20>::hash::operator()(FixedHash<20> const& value) const
+{
+	const uint64_t*data = (const uint64_t*)value.data();
+	uint64_t hash = data[0];
+	hash ^= data[1];
+	hash ^= ((const uint32_t*)value.data())[4];
+	return (size_t)hash;
+}
+
 /// Fast std::hash compatible hash function object for h256.
 template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
 {
@@ -226,6 +236,21 @@ template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& va
 	return (size_t)hash;
 }
 
+/// Fast std::hash compatible hash function object for h512.
+template<> inline size_t FixedHash<64>::hash::operator()(FixedHash<64> const& value) const
+{
+	const uint64_t*data = (const uint64_t*)value.data();
+	uint64_t hash = data[0];
+	hash ^= data[1];
+	hash ^= data[2];
+	hash ^= data[3];
+	hash ^= data[4];
+	hash ^= data[5];
+	hash ^= data[6];
+	hash ^= data[7];
+	return (size_t)hash;
+}
+
 /// Stream I/O for the FixedHash class.
 template 
 inline std::ostream& operator<<(std::ostream& _out, FixedHash const& _h)
@@ -251,6 +276,8 @@ using h256s = std::vector;
 using h160s = std::vector;
 using h256Set = std::set;
 using h160Set = std::set;
+using h256Hash = std::unordered_set;
+using h160Hash = std::unordered_set;
 
 /// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes.
 inline h160 right160(h256 const& _t)
@@ -282,6 +309,9 @@ inline std::string toString(h256s const& _bs)
 
 namespace std
 {
-	/// Forward std::hash to dev::h256::hash.
+	/// Forward std::hash to dev::FixedHash::hash.
+	template<> struct hash: dev::h64::hash {};
+	template<> struct hash: dev::h160::hash {};
 	template<> struct hash: dev::h256::hash {};
+	template<> struct hash: dev::h512::hash {};
 }
diff --git a/libdevcore/Log.h b/libdevcore/Log.h
index f42e9cbdd..20ad9fd20 100644
--- a/libdevcore/Log.h
+++ b/libdevcore/Log.h
@@ -164,6 +164,30 @@ public:
 		}
 		m_sstr << EthLime "}" EthReset;
 	}
+	template  void append(std::unordered_set const& _t)
+	{
+		m_sstr << EthYellow "{" EthReset;
+		int n = 0;
+		for (auto const& i: _t)
+		{
+			m_sstr << (n++ ? EthYellow ", " EthReset : "");
+			append(i);
+		}
+		m_sstr << EthYellow "}" EthReset;
+	}
+	template  void append(std::unordered_map const& _t)
+	{
+		m_sstr << EthLime "{" EthReset;
+		int n = 0;
+		for (auto const& i: _t)
+		{
+			m_sstr << (n++ ? EthLime ", " EthReset : "");
+			append(i.first);
+			m_sstr << (n++ ? EthLime ": " EthReset : "");
+			append(i.second);
+		}
+		m_sstr << EthLime "}" EthReset;
+	}
 	template  void append(std::pair const& _t)
 	{
 		m_sstr << EthPurple "(" EthReset;
diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h
index ac5e2ef1e..6e46807ab 100644
--- a/libdevcore/RLP.h
+++ b/libdevcore/RLP.h
@@ -362,6 +362,7 @@ public:
 	template  RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
 	template  RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
 	template  RLPStream& append(std::set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
+	template  RLPStream& append(std::unordered_set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
 	template  RLPStream& append(std::pair const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; }
 
 	/// Appends a list.
diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h
index 50072c1bf..b854e76a3 100644
--- a/libdevcrypto/Common.h
+++ b/libdevcrypto/Common.h
@@ -68,8 +68,8 @@ extern Address ZeroAddress;
 /// A vector of Ethereum addresses.
 using Addresses = h160s;
 
-/// A set of Ethereum addresses.
-using AddressSet = std::set;
+/// A hash table of Ethereum addresses.
+using AddressHash = std::unordered_set;
 
 /// A vector of secrets.
 using Secrets = h256s;
diff --git a/libdevcrypto/MemoryDB.cpp b/libdevcrypto/MemoryDB.cpp
index 907e6abe6..4b08db083 100644
--- a/libdevcrypto/MemoryDB.cpp
+++ b/libdevcrypto/MemoryDB.cpp
@@ -30,9 +30,9 @@ namespace dev
 const char* DBChannel::name() { return "TDB"; }
 const char* DBWarn::name() { return "TDB"; }
 
-std::map MemoryDB::get() const
+std::unordered_map MemoryDB::get() const
 {
-	std::map ret;
+	std::unordered_map ret;
 	for (auto const& i: m_main)
 		if (!m_enforceRefs || i.second.second > 0)
 			ret.insert(make_pair(i.first, i.second.first));
@@ -112,9 +112,9 @@ void MemoryDB::purge()
 			it = m_main.erase(it);
 }
 
-set MemoryDB::keys() const
+h256Hash MemoryDB::keys() const
 {
-	set ret;
+	h256Hash ret;
 	for (auto const& i: m_main)
 		if (i.second.second)
 			ret.insert(i.first);
diff --git a/libdevcrypto/MemoryDB.h b/libdevcrypto/MemoryDB.h
index 71428ecdb..3169d8fbc 100644
--- a/libdevcrypto/MemoryDB.h
+++ b/libdevcrypto/MemoryDB.h
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -45,7 +45,7 @@ public:
 	MemoryDB() {}
 
 	void clear() { m_main.clear(); }	// WARNING !!!! didn't originally clear m_refCount!!!
-	std::map get() const;
+	std::unordered_map get() const;
 
 	std::string lookup(h256 const& _h) const;
 	bool exists(h256 const& _h) const;
@@ -57,11 +57,11 @@ public:
 	void removeAux(h256 const& _h) { m_aux[_h].second = false; }
 	void insertAux(h256 const& _h, bytesConstRef _v) { m_aux[_h] = make_pair(_v.toBytes(), true); }
 
-	std::set keys() const;
+	h256Hash keys() const;
 
 protected:
-	std::map> m_main;
-	std::map> m_aux;
+	std::unordered_map> m_main;
+	std::unordered_map> m_aux;
 
 	mutable bool m_enforceRefs = false;
 };
diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h
index ef628d20b..ff2bcc589 100644
--- a/libdevcrypto/TrieDB.h
+++ b/libdevcrypto/TrieDB.h
@@ -26,7 +26,6 @@
 #include 
 #pragma warning(pop)
 
-#include 
 #include 
 #include 
 #include 
@@ -105,7 +104,7 @@ public:
 
 	void debugPrint() {}
 
-	void descendKey(h256 _k, std::set& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const
+	void descendKey(h256 _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const
 	{
 		_keyMask.erase(_k);
 		if (_k == m_root && _k == c_shaNull)	// root allowed to be empty
@@ -113,7 +112,7 @@ public:
 		descendList(RLP(node(_k)), _keyMask, _wasExt, _out, _indent);	// if not, it must be a list
 	}
 
-	void descendEntry(RLP const& _r, std::set& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
+	void descendEntry(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
 	{
 		if (_r.isData() && _r.size() == 32)
 			descendKey(_r.toHash(), _keyMask, _wasExt, _out, _indent);
@@ -123,7 +122,7 @@ public:
 			BOOST_THROW_EXCEPTION(InvalidTrie());
 	}
 
-	void descendList(RLP const& _r, std::set& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
+	void descendList(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
 	{
 		if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out))
 		{
@@ -144,9 +143,9 @@ public:
 			BOOST_THROW_EXCEPTION(InvalidTrie());
 	}
 
-	std::set leftOvers(std::ostream* _out = nullptr) const
+	h256Hash leftOvers(std::ostream* _out = nullptr) const
 	{
-		std::set k = m_db->keys();
+		h256Hash k = m_db->keys();
 		descendKey(m_root, k, false, _out);
 		return k;
 	}
@@ -431,7 +430,7 @@ public:
 	void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(_key, _value); m_secure.insert(_key, _value); syncRoot(); }
 	void remove(bytesConstRef _key) { Super::remove(_key); m_secure.remove(_key); syncRoot(); }
 
-	std::set leftOvers(std::ostream* = nullptr) const { return std::set{}; }
+	h256Hash leftOvers(std::ostream* = nullptr) const { return h256Hash{}; }
 	bool check(bool) const { return m_secure.check(false) && Super::check(false); }
 
 private:
diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h
index 0389697f5..c90ee048e 100644
--- a/libethcore/EthashAux.h
+++ b/libethcore/EthashAux.h
@@ -75,12 +75,12 @@ private:
 	static EthashAux* s_this;
 	RecursiveMutex x_this;
 
-	std::map> m_lights;
-	std::map> m_fulls;
+	std::unordered_map> m_lights;
+	std::unordered_map> m_fulls;
 	FullType m_lastUsedFull;
 
 	Mutex x_epochs;
-	std::map m_epochs;
+	std::unordered_map m_epochs;
 	h256s m_seedHashes;
 };
 
diff --git a/libethereum/Account.h b/libethereum/Account.h
index 2cc962baa..660dc0a4c 100644
--- a/libethereum/Account.h
+++ b/libethereum/Account.h
@@ -134,8 +134,8 @@ public:
 	/// which encodes the base-state of the account's storage (upon which the storage is overlaid).
 	h256 baseRoot() const { assert(m_storageRoot); return m_storageRoot; }
 
-	/// @returns the storage overlay as a simple map.
-	std::map const& storageOverlay() const { return m_storageOverlay; }
+	/// @returns the storage overlay as a simple hash map.
+	std::unordered_map const& storageOverlay() const { return m_storageOverlay; }
 
 	/// Set a key/value pair in the account's storage. This actually goes into the overlay, for committing
 	/// to the trie later.
@@ -194,7 +194,7 @@ private:
 	h256 m_codeHash = EmptySHA3;
 
 	/// The map with is overlaid onto whatever storage is implied by the m_storageRoot in the trie.
-	std::map m_storageOverlay;
+	std::unordered_map m_storageOverlay;
 
 	/// The associated code for this account. The SHA3 of this should be equal to m_codeHash unless m_codeHash
 	/// equals c_contractConceptionCodeHash.
diff --git a/libethereum/AccountDiff.h b/libethereum/AccountDiff.h
index dd494c0a5..22107b958 100644
--- a/libethereum/AccountDiff.h
+++ b/libethereum/AccountDiff.h
@@ -62,7 +62,7 @@ struct AccountDiff
 	Diff exist;						///< The account's existance; was it created/deleted or not?
 	Diff balance;						///< The account's balance; did it alter?
 	Diff nonce;						///< The account's nonce; did it alter?
-	std::map> storage;		///< The account's storage addresses; each has its own Diff.
+	std::unordered_map> storage;		///< The account's storage addresses; each has its own Diff.
 	Diff code;						///< The account's code; in general this should only have changed if exist also changed.
 };
 
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index 192cff34c..607fc586c 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -961,10 +961,10 @@ vector BlockChain::withBlockBloom(LogBloom const& _b, unsigned _earlie
 	return ret;
 }
 
-h256Set BlockChain::allUnclesFrom(h256 const& _parent) const
+h256Hash BlockChain::allUnclesFrom(h256 const& _parent) const
 {
 	// Get all uncles cited given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
-	h256Set ret;
+	h256Hash ret;
 	h256 p = _parent;
 	for (unsigned i = 0; i < 6 && p != m_genesisHash; ++i, p = details(p).parent)
 	{
diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h
index 12e1fc785..e77369534 100644
--- a/libethereum/BlockChain.h
+++ b/libethereum/BlockChain.h
@@ -72,7 +72,7 @@ struct BlockChainWarn: public LogChannel { static const char* name(); static con
 struct BlockChainDebug: public LogChannel { static const char* name(); static const int verbosity = 0; };
 
 // TODO: Move all this Genesis stuff into Genesis.h/.cpp
-std::map const& genesisState();
+std::unordered_map const& genesisState();
 
 ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0);
 
@@ -206,7 +206,7 @@ public:
 	/// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
 	/// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5
 	/// togther with all their quoted uncles.
-	h256Set allUnclesFrom(h256 const& _parent) const;
+	h256Hash allUnclesFrom(h256 const& _parent) const;
 
 	/// Run through database and verify all blocks by reevaluating.
 	/// Will call _progress with the progress in this operation first param done, second total.
diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h
index d9cb0ed53..a4e44b390 100644
--- a/libethereum/BlockQueue.h
+++ b/libethereum/BlockQueue.h
@@ -106,15 +106,15 @@ private:
 
 	bool invariants() const override;
 
-	mutable boost::shared_mutex m_lock;						///< General lock.
-	std::set m_drainingSet;							///< All blocks being imported.
-	std::set m_readySet;								///< All blocks ready for chain-import.
-	std::vector> m_ready;			///< List of blocks, in correct order, ready for chain-import.
-	std::set m_unknownSet;							///< Set of all blocks whose parents are not ready/in-chain.
-	std::multimap> m_unknown;	///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
-	std::set m_knownBad;								///< Set of blocks that we know will never be valid.
-	std::multimap> m_future;///< Set of blocks that are not yet valid.
-	Signal m_onReady;										///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
+	mutable boost::shared_mutex m_lock;									///< General lock.
+	h256Hash m_drainingSet;												///< All blocks being imported.
+	h256Hash m_readySet;												///< All blocks ready for chain-import.
+	std::vector> m_ready;						///< List of blocks, in correct order, ready for chain-import.
+	h256Hash m_unknownSet;												///< Set of all blocks whose parents are not ready/in-chain.
+	std::unordered_multimap> m_unknown;	///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
+	h256Hash m_knownBad;												///< Set of blocks that we know will never be valid.
+	std::multimap> m_future;			///< Set of blocks that are not yet valid. Ordered by timestamp
+	Signal m_onReady;													///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
 };
 
 }
diff --git a/libethereum/CachedAddressState.cpp b/libethereum/CachedAddressState.cpp
index e2fadc8b5..a25017793 100644
--- a/libethereum/CachedAddressState.cpp
+++ b/libethereum/CachedAddressState.cpp
@@ -51,9 +51,9 @@ bytes CachedAddressState::code() const
 	return h == EmptySHA3 ? bytes() : asBytes(m_o->lookup(h));
 }
 
-std::map CachedAddressState::storage() const
+std::unordered_map CachedAddressState::storage() const
 {
-	std::map ret;
+	std::unordered_map ret;
 	if (m_r)
 	{
 		SecureTrieDB memdb(const_cast(m_o), m_r[2].toHash());		// promise we won't alter the overlay! :)
diff --git a/libethereum/CachedAddressState.h b/libethereum/CachedAddressState.h
index 8a3c3a607..2a34c1b34 100644
--- a/libethereum/CachedAddressState.h
+++ b/libethereum/CachedAddressState.h
@@ -47,7 +47,7 @@ public:
 	bytes code() const;
 
 	// TODO: DEPRECATE.
-	std::map storage() const;
+	std::unordered_map storage() const;
 
 	AccountDiff diff(CachedAddressState const& _c);
 
diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp
index 2cc1d24dc..f1de7292b 100644
--- a/libethereum/CanonBlockChain.cpp
+++ b/libethereum/CanonBlockChain.cpp
@@ -41,9 +41,9 @@ namespace js = json_spirit;
 
 #define ETH_CATCH 1
 
-std::map const& dev::eth::genesisState()
+std::unordered_map const& dev::eth::genesisState()
 {
-	static std::map s_ret;
+	static std::unordered_map s_ret;
 
 	if (s_ret.empty())
 	{
diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h
index 619af87eb..df4ac2d88 100644
--- a/libethereum/CanonBlockChain.h
+++ b/libethereum/CanonBlockChain.h
@@ -45,7 +45,7 @@ namespace eth
 {
 
 // TODO: Move all this Genesis stuff into Genesis.h/.cpp
-std::map const& genesisState();
+std::unordered_map const& genesisState();
 
 /**
  * @brief Implements the blockchain database. All data this gives is disk-backed.
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index 01426527f..a43c98aa2 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -308,7 +308,7 @@ void Client::killChain()
 
 void Client::clearPending()
 {
-	h256Set changeds;
+	h256Hash changeds;
 	DEV_WRITE_GUARDED(x_postMine)
 	{
 		if (!m_postMine.pending().size())
@@ -345,7 +345,7 @@ static S& filtersStreamOut(S& _out, T const& _fs)
 	return _out;
 }
 
-void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash)
+void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _transactionHash)
 {
 	Guard l(x_filtersWatches);
 	for (pair& i: m_filters)
@@ -363,7 +363,7 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& i
 		}
 }
 
-void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed)
+void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed)
 {
 	// TODO: more precise check on whether the txs match.
 	auto d = m_bc.info(_block);
@@ -496,7 +496,7 @@ void Client::syncTransactionQueue()
 	// returns TransactionReceipts, once for each transaction.
 	cwork << "postSTATE <== TQ";
 
-	h256Set changeds;
+	h256Hash changeds;
 	TransactionReceipts newPendingReceipts;
 
 	DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
@@ -552,7 +552,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
 	if (auto h = m_host.lock())
 		h->noteNewBlocks();
 
-	h256Set changeds;
+	h256Hash changeds;
 	for (auto const& h: _ir.first)
 		appendFromNewBlock(h, changeds);
 	changeds.insert(ChainChangedFilter);
@@ -631,7 +631,7 @@ void Client::startMining()
 	onPostStateChanged();
 }
 
-void Client::noteChanged(h256Set const& _filters)
+void Client::noteChanged(h256Hash const& _filters)
 {
 	Guard l(x_filtersWatches);
 	if (_filters.size())
diff --git a/libethereum/Client.h b/libethereum/Client.h
index 946825828..e40356f86 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -228,15 +228,15 @@ protected:
 
 	/// Collate the changed filters for the bloom filter of the given pending transaction.
 	/// Insert any filters that are activated into @a o_changed.
-	void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _sha3);
+	void appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _sha3);
 
 	/// Collate the changed filters for the hash of the given block.
 	/// Insert any filters that are activated into @a o_changed.
-	void appendFromNewBlock(h256 const& _blockHash, h256Set& io_changed);
+	void appendFromNewBlock(h256 const& _blockHash, h256Hash& io_changed);
 
 	/// Record that the set of filters @a _filters have changed.
 	/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
-	void noteChanged(h256Set const& _filters);
+	void noteChanged(h256Hash const& _filters);
 
 private:
 	/// Called when Worker is starting.
diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp
index 136239cf3..8b3cd416f 100644
--- a/libethereum/ClientBase.cpp
+++ b/libethereum/ClientBase.cpp
@@ -147,7 +147,7 @@ h256 ClientBase::codeHashAt(Address _a, BlockNumber _block) const
 	return asOf(_block).codeHash(_a);
 }
 
-map ClientBase::storageAt(Address _a, BlockNumber _block) const
+unordered_map ClientBase::storageAt(Address _a, BlockNumber _block) const
 {
 	return asOf(_block).storage(_a);
 }
diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h
index fc0b301ad..87888affe 100644
--- a/libethereum/ClientBase.h
+++ b/libethereum/ClientBase.h
@@ -100,7 +100,7 @@ public:
 	virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override;
 	virtual bytes codeAt(Address _a, BlockNumber _block) const override;
 	virtual h256 codeHashAt(Address _a, BlockNumber _block) const override;
-	virtual std::map storageAt(Address _a, BlockNumber _block) const override;
+	virtual std::unordered_map storageAt(Address _a, BlockNumber _block) const override;
 
 	virtual LocalisedLogEntries logs(unsigned _watchId) const override;
 	virtual LocalisedLogEntries logs(LogFilter const& _filter) const override;
@@ -172,9 +172,9 @@ protected:
 	TransactionQueue m_tq;							///< Maintains a list of incoming transactions not yet in a block on the blockchain.
 
 	// filters
-	mutable Mutex x_filtersWatches;					///< Our lock.
-	std::map m_filters;		///< The dictionary of filters that are active.
-	std::map m_watches;		///< Each and every watch - these reference a filter.
+	mutable Mutex x_filtersWatches;							///< Our lock.
+	std::unordered_map m_filters;	///< The dictionary of filters that are active.
+	std::map m_watches;				///< Each and every watch - these reference a filter.
 };
 
 }}
diff --git a/libethereum/DownloadMan.cpp b/libethereum/DownloadMan.cpp
index 1b73dca5b..05d0a533e 100644
--- a/libethereum/DownloadMan.cpp
+++ b/libethereum/DownloadMan.cpp
@@ -39,7 +39,7 @@ DownloadSub::~DownloadSub()
 	}
 }
 
-h256Set DownloadSub::nextFetch(unsigned _n)
+h256Hash DownloadSub::nextFetch(unsigned _n)
 {
 	Guard l(m_fetch);
 
@@ -51,7 +51,7 @@ h256Set DownloadSub::nextFetch(unsigned _n)
 	m_remaining.clear();
 
 	if (!m_man || m_man->chainEmpty())
-		return h256Set();
+		return h256Hash();
 
 	m_asked = (~(m_man->taken() + m_attempted)).lowest(_n);
 	if (m_asked.empty())
diff --git a/libethereum/DownloadMan.h b/libethereum/DownloadMan.h
index 82e0f09e2..2b41e660b 100644
--- a/libethereum/DownloadMan.h
+++ b/libethereum/DownloadMan.h
@@ -21,9 +21,9 @@
 
 #pragma once
 
-#include 
 #include 
-#include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -46,7 +46,7 @@ public:
 	~DownloadSub();
 
 	/// Finished last fetch - grab the next bunch of block hashes to download.
-	h256Set nextFetch(unsigned _n);
+	h256Hash nextFetch(unsigned _n);
 
 	/// Note that we've received a particular block. @returns true if we had asked for it but haven't received it yet.
 	bool noteBlock(h256 _hash);
@@ -71,8 +71,8 @@ private:
 	DownloadMan* m_man = nullptr;
 
 	mutable Mutex m_fetch;
-	h256Set m_remaining;
-	std::map m_indices;
+	h256Hash m_remaining;
+	std::unordered_map m_indices;
 	RangeMask m_asked;
 	RangeMask m_attempted;
 };
@@ -155,7 +155,7 @@ private:
 	RangeMask m_blocksGot;
 
 	mutable SharedMutex x_subs;
-	std::set m_subs;
+	std::unordered_set m_subs;
 };
 
 }
diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp
index 299984a16..72ee1854d 100644
--- a/libethereum/EthereumHost.cpp
+++ b/libethereum/EthereumHost.cpp
@@ -21,7 +21,6 @@
 
 #include "EthereumHost.h"
 
-#include 
 #include 
 #include 
 #include 
@@ -184,7 +183,7 @@ void EthereumHost::doWork()
 void EthereumHost::maintainTransactions()
 {
 	// Send any new transactions.
-	map, h256s> peerTransactions;
+	unordered_map, h256s> peerTransactions;
 	auto ts = m_tq.transactions();
 	for (auto const& i: ts)
 	{
diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h
index baa850b5c..d53c3cc79 100644
--- a/libethereum/EthereumHost.h
+++ b/libethereum/EthereumHost.h
@@ -22,9 +22,9 @@
 #pragma once
 
 #include 
-#include 
+#include 
 #include 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -97,7 +97,7 @@ private:
 	/// Get a bunch of needed blocks.
 	/// Removes them from our list of needed blocks.
 	/// @returns empty if there's no more blocks left to fetch, otherwise the blocks to fetch.
-	h256Set neededBlocks(h256Set const& _exclude);
+	h256Hash neededBlocks(h256Hash const& _exclude);
 
 	///	Check to see if the network peer-state initialisation has happened.
 	bool isInitialised() const { return (bool)m_latestBlockSent; }
@@ -121,9 +121,9 @@ private:
 	DownloadMan m_man;
 
 	h256 m_latestBlockSent;
-	h256Set m_transactionsSent;
+	h256Hash m_transactionsSent;
 
-	std::set m_banned;
+	std::unordered_set m_banned;
 
 	bool m_newTransactions = false;
 	bool m_newBlocks = false;
diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h
index 75ebab02f..54f7ad829 100644
--- a/libethereum/EthereumPeer.h
+++ b/libethereum/EthereumPeer.h
@@ -23,7 +23,6 @@
 
 #include 
 #include 
-#include 
 #include 
 #include 
 
@@ -140,9 +139,9 @@ private:
 	bool m_requireTransactions = false;
 
 	Mutex x_knownBlocks;
-	h256Set m_knownBlocks;					///< Blocks that the peer already knows about (that don't need to be sent to them).
+	h256Hash m_knownBlocks;					///< Blocks that the peer already knows about (that don't need to be sent to them).
 	Mutex x_knownTransactions;
-	h256Set m_knownTransactions;			///< Transactions that the peer already knows of.
+	h256Hash m_knownTransactions;			///< Transactions that the peer already knows of.
 
 };
 
diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h
index 8807bcd58..1a2d180dd 100644
--- a/libethereum/ExtVM.h
+++ b/libethereum/ExtVM.h
@@ -91,8 +91,8 @@ public:
 	State& state() const { return m_s; }
 
 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.
+	State& m_s;											///< A reference to the base state.
+	std::unordered_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 ba68e976e..f36d0f2c1 100644
--- a/libethereum/Interface.h
+++ b/libethereum/Interface.h
@@ -100,14 +100,14 @@ public:
 	u256 stateAt(Address _a, u256 _l) const { return stateAt(_a, _l, m_default); }
 	bytes codeAt(Address _a) const { return codeAt(_a, m_default); }
 	h256 codeHashAt(Address _a) const { return codeHashAt(_a, m_default); }
-	std::map storageAt(Address _a) const { return storageAt(_a, m_default); }
+	std::unordered_map storageAt(Address _a) const { return storageAt(_a, m_default); }
 
 	virtual u256 balanceAt(Address _a, BlockNumber _block) const = 0;
 	virtual u256 countAt(Address _a, BlockNumber _block) const = 0;
 	virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const = 0;
 	virtual bytes codeAt(Address _a, BlockNumber _block) const = 0;
 	virtual h256 codeHashAt(Address _a, BlockNumber _block) const = 0;
-	virtual std::map storageAt(Address _a, BlockNumber _block) const = 0;
+	virtual std::unordered_map storageAt(Address _a, BlockNumber _block) const = 0;
 
 	// [LOGS API]
 	
diff --git a/libethereum/LogFilter.h b/libethereum/LogFilter.h
index 304fab317..97ff5a3b1 100644
--- a/libethereum/LogFilter.h
+++ b/libethereum/LogFilter.h
@@ -67,8 +67,8 @@ public:
 	friend std::ostream& dev::eth::operator<<(std::ostream& _out, dev::eth::LogFilter const& _s);
 
 private:
-	AddressSet m_addresses;
-	std::array m_topics;
+	AddressHash m_addresses;
+	std::array m_topics;
 	unsigned m_earliest = 0;
 	unsigned m_latest = LatestBlock;
 };
diff --git a/libethereum/Precompiled.cpp b/libethereum/Precompiled.cpp
index 0fd5cb45b..cdcb4a46a 100644
--- a/libethereum/Precompiled.cpp
+++ b/libethereum/Precompiled.cpp
@@ -81,7 +81,7 @@ static bytes identityCode(bytesConstRef _in)
 	return _in.toBytes();
 }
 
-static const std::map c_precompiled =
+static const std::unordered_map c_precompiled =
 {
 	{ 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }},
 	{ 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }},
@@ -89,7 +89,7 @@ static const std::map c_precompiled =
 	{ 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }}
 };
 
-std::map const& dev::eth::precompiled()
+std::unordered_map const& dev::eth::precompiled()
 {
 	return c_precompiled;
 }
diff --git a/libethereum/Precompiled.h b/libethereum/Precompiled.h
index c65cd9a63..bded27386 100644
--- a/libethereum/Precompiled.h
+++ b/libethereum/Precompiled.h
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include 
+#include 
 #include 
 #include 
 
@@ -38,7 +38,7 @@ struct PrecompiledAddress
 };
 
 /// Info on precompiled contract accounts baked into the protocol.
-std::map const& precompiled();
+std::unordered_map const& precompiled();
 
 }
 }
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 83a78e1e8..9156820b9 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -208,9 +208,9 @@ StateDiff State::diff(State const& _c) const
 {
 	StateDiff ret;
 
-	std::set
ads; - std::set
trieAds; - std::set
trieAdsD; + std::unordered_set
ads; + std::unordered_set
trieAds; + std::unordered_set
trieAdsD; auto trie = SecureTrieDB(const_cast(&m_db), rootHash()); auto trieD = SecureTrieDB(const_cast(&_c.m_db), _c.rootHash()); @@ -246,7 +246,7 @@ void State::ensureCached(Address _a, bool _requireCode, bool _forceCreate) const ensureCached(m_cache, _a, _requireCode, _forceCreate); } -void State::ensureCached(std::map& _cache, Address _a, bool _requireCode, bool _forceCreate) const +void State::ensureCached(std::unordered_map& _cache, Address _a, bool _requireCode, bool _forceCreate) const { auto it = _cache.find(_a); if (it == _cache.end()) @@ -426,10 +426,10 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const return ret; } -map State::addresses() const +unordered_map State::addresses() const { #if ETH_FATDB - map ret; + unordered_map ret; for (auto i: m_cache) if (i.second.isAlive()) ret[i.first] = i.second.balance(); @@ -649,9 +649,9 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement if (rlp[2].itemCount() > 2) BOOST_THROW_EXCEPTION(TooManyUncles()); - set nonces = { m_currentBlock.nonce }; + unordered_set nonces = { m_currentBlock.nonce }; vector rewarded; - set knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); + h256Hash knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); for (auto const& i: rlp[2]) { @@ -805,7 +805,7 @@ void State::commitToMine(BlockChain const& _bc) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. // cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - set knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); + h256Hash knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); auto p = m_previousBlock.parentHash; for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { @@ -1016,9 +1016,9 @@ u256 State::storage(Address _id, u256 _memory) const return ret; } -map State::storage(Address _id) const +unordered_map State::storage(Address _id) const { - map ret; + unordered_map ret; ensureCached(_id, false, false); auto it = m_cache.find(_id); diff --git a/libethereum/State.h b/libethereum/State.h index e3468c24c..74d75685c 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -22,7 +22,6 @@ #pragma once #include -#include #include #include #include @@ -142,7 +141,7 @@ public: /// @returns the set containing all addresses currently in use in Ethereum. /// @throws InterfaceNotSupported if compiled without ETH_FATDB. - std::map addresses() const; + std::unordered_map addresses() const; /// Get the header information on the present block. BlockInfo const& info() const { return m_currentBlock; } @@ -238,8 +237,8 @@ public: /// Get the storage of an account. /// @note This is expensive. Don't use it unless you need to. - /// @returns std::map if no account exists at that address. - std::map storage(Address _contract) const; + /// @returns std::unordered_map if no account exists at that address. + std::unordered_map storage(Address _contract) const; /// Get the code of an account. /// @returns bytes() if no account exists at that address. @@ -263,7 +262,7 @@ public: Transactions const& pending() const { return m_transactions; } /// Get the list of hashes of pending transactions. - h256Set const& pendingHashes() const { return m_transactionSet; } + h256Hash const& pendingHashes() const { return m_transactionSet; } /// Get the transaction receipt for the transaction of the given index. TransactionReceipt const& receipt(unsigned _i) const { return m_receipts[_i]; } @@ -334,7 +333,7 @@ private: void ensureCached(Address _a, bool _requireCode, bool _forceCreate) const; /// Retrieve all information about a given address into a cache. - void ensureCached(std::map& _cache, Address _a, bool _requireCode, bool _forceCreate) const; + void ensureCached(std::unordered_map& _cache, Address _a, bool _requireCode, bool _forceCreate) const; /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. @@ -355,10 +354,10 @@ private: SecureTrieDB m_state; ///< Our state tree, as an OverlayDB DB. Transactions m_transactions; ///< The current list of transactions that we've included in the state. TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts. - std::set m_transactionSet; ///< The set of transaction hashes that we've included in the state. + h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state. OverlayDB m_lastTx; - mutable std::map m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed. + mutable std::unordered_map m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed. BlockInfo m_previousBlock; ///< The previous block's information. BlockInfo m_currentBlock; ///< The current block's information. @@ -380,7 +379,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -void commit(std::map const& _cache, DB& _db, SecureTrieDB& _state) +void commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) { for (auto const& i: _cache) if (i.second.isDirty()) diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index 69e1c935f..50fcea574 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -55,7 +55,7 @@ public: void drop(h256 const& _txHash); - std::map transactions() const { ReadGuard l(m_lock); return m_current; } + std::unordered_map transactions() const { ReadGuard l(m_lock); return m_current; } std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); } u256 maxNonce(Address const& _a) const; @@ -72,14 +72,14 @@ private: void insertCurrent_WITH_LOCK(std::pair const& _p); bool removeCurrent_WITH_LOCK(h256 const& _txHash); - mutable SharedMutex m_lock; ///< General lock. - std::set m_known; ///< Hashes of transactions in both sets. - std::map m_current; ///< Map of SHA3(tx) to tx. - std::multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. - std::map> m_callbacks; ///< Called once. - std::set m_dropped; ///< Transactions that have previously been dropped. - std::multimap m_senders; ///< Mapping from the sender address to the transaction hash; useful for determining the nonce of a given sender. - Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. + mutable SharedMutex m_lock; ///< General lock. + h256Hash m_known; ///< Hashes of transactions in both sets. + std::unordered_map m_current; ///< Map of SHA3(tx) to tx. + std::unordered_multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. + std::unordered_map> m_callbacks; ///< Called once. + h256Hash m_dropped; ///< Transactions that have previously been dropped. + std::multimap m_senders; ///< Mapping from the sender address to the transaction hash; useful for determining the nonce of a given sender. + Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. }; } diff --git a/libethereum/TransactionReceipt.h b/libethereum/TransactionReceipt.h index 1e0663054..0a0b154f4 100644 --- a/libethereum/TransactionReceipt.h +++ b/libethereum/TransactionReceipt.h @@ -22,7 +22,6 @@ #pragma once #include -#include #include #include #include diff --git a/libp2p/Common.h b/libp2p/Common.h index 378064e7d..96b8b9683 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -203,3 +203,26 @@ struct Node /// Simple stream output for a NodeIPEndpoint. std::ostream& operator<<(std::ostream& _out, dev::p2p::NodeIPEndpoint const& _ep); } + +/// std::hash for asio::adress +namespace std +{ + +template <> struct hash +{ + size_t operator()(bi::address const& _a) const + { + if (_a.is_v4()) + return _a.to_v4().to_ulong(); + if (_a.is_v6()) + { + auto const& range = _a.to_v6().to_bytes(); + return boost::hash_range(range.begin(), range.end()); + } + if (_a.is_unspecified()) + return static_cast(0x3487194039229152ul); // Some random value + return std::hash()(_a.to_string()); + } +}; + +} diff --git a/libp2p/Host.h b/libp2p/Host.h index 41f4d1e72..b9af0e8b0 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -227,7 +227,7 @@ private: std::shared_ptr m_nodeTable; ///< Node table (uses kademlia-like discovery). /// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer; - std::map> m_peers; + std::unordered_map> m_peers; /// Peers we try to connect regardless of p2p network. std::set m_requiredPeers; @@ -235,7 +235,7 @@ private: /// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run()) /// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method. - mutable std::map> m_sessions; + mutable std::unordered_map> m_sessions; mutable RecursiveMutex x_sessions; std::list> m_connecting; ///< Pending connections. diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index 847e6a42d..d8ab90a20 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -154,12 +154,12 @@ int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _acceptor.bind(endpoint); _acceptor.listen(); retport = _acceptor.local_endpoint().port(); + assert(retport == _netPrefs.listenPort); } catch (...) { clog(NetWarn) << "Couldn't start accepting connections on host. Failed to accept socket.\n" << boost::current_exception_diagnostic_information(); } - assert(retport == _netPrefs.listenPort); return retport; } return retport; diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 42f1cad02..7a68cae10 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -232,7 +232,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) unsigned head = distance(m_node.id, _target); unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins; - map>> found; + unordered_multimap> found; unsigned count = 0; // if d is 0, then we roll look forward, if last, we reverse, else, spread from d @@ -244,7 +244,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) if (auto p = n.lock()) { if (count < s_bucketSize) - found[distance(_target, p->id)].push_back(p); + found.insert(make_pair(distance(_target, p->id), p)); else break; } @@ -254,7 +254,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) if (auto p = n.lock()) { if (count < s_bucketSize) - found[distance(_target, p->id)].push_back(p); + found.insert(make_pair(distance(_target, p->id), p)); else break; } @@ -271,7 +271,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) if (auto p = n.lock()) { if (count < s_bucketSize) - found[distance(_target, p->id)].push_back(p); + found.insert(make_pair(distance(_target, p->id), p)); else break; } @@ -285,7 +285,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) if (auto p = n.lock()) { if (count < s_bucketSize) - found[distance(_target, p->id)].push_back(p); + found.insert(make_pair(distance(_target, p->id), p)); else break; } @@ -293,10 +293,9 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) } vector> ret; - for (auto& nodes: found) - for (auto n: nodes.second) - if (n->endpoint.isAllowed()) - ret.push_back(n); + for (auto n: found) + if (n.second->endpoint.isAllowed()) + ret.push_back(n.second); return move(ret); } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 95028db2b..f09e27857 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -80,7 +80,7 @@ protected: Mutex x_events; std::list m_nodeEventHandler; - std::map m_events; + std::unordered_map m_events; }; class NodeTable; @@ -254,32 +254,32 @@ private: /// Purges and pings nodes for any buckets which haven't been touched for c_bucketRefresh seconds. void doRefreshBuckets(boost::system::error_code const& _ec); - std::unique_ptr m_nodeEventHandler; ///< Event handler for node events. + std::unique_ptr m_nodeEventHandler; ///< Event handler for node events. - Node m_node; ///< This node. - Secret m_secret; ///< This nodes secret key. + Node m_node; ///< This node. + Secret m_secret; ///< This nodes secret key. - mutable Mutex x_nodes; ///< LOCK x_state first if both locks are required. Mutable for thread-safe copy in nodes() const. - std::map> m_nodes; ///< Nodes + mutable Mutex x_nodes; ///< LOCK x_state first if both locks are required. Mutable for thread-safe copy in nodes() const. + std::unordered_map> m_nodes; ///< Nodes - mutable Mutex x_state; ///< LOCK x_state first if both x_nodes and x_state locks are required. - std::array m_state; ///< State of p2p node network. + mutable Mutex x_state; ///< LOCK x_state first if both x_nodes and x_state locks are required. + std::array m_state; ///< State of p2p node network. - Mutex x_evictions; ///< LOCK x_nodes first if both x_nodes and x_evictions locks are required. - std::deque m_evictions; ///< Eviction timeouts. + Mutex x_evictions; ///< LOCK x_nodes first if both x_nodes and x_evictions locks are required. + std::deque m_evictions; ///< Eviction timeouts. - Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required. - std::map m_pubkDiscoverPings; ///< List of pending pings where node entry wasn't created due to unkown pubk. + Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required. + std::unordered_map m_pubkDiscoverPings; ///< List of pending pings where node entry wasn't created due to unkown pubk. Mutex x_findNodeTimeout; - std::list m_findNodeTimeout; ///< Timeouts for pending Ping and FindNode requests. + std::list m_findNodeTimeout; ///< Timeouts for pending Ping and FindNode requests. - ba::io_service& m_io; ///< Used by bucket refresh timer. - std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. - NodeSocket* m_socketPointer; ///< Set to m_socket.get(). Socket is created in constructor and disconnected in destructor to ensure access to pointer is safe. + ba::io_service& m_io; ///< Used by bucket refresh timer. + std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. + NodeSocket* m_socketPointer; ///< Set to m_socket.get(). Socket is created in constructor and disconnected in destructor to ensure access to pointer is safe. - boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. - boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. + boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. + boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. }; inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index fa5ec1c27..c558c71f3 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -211,7 +211,7 @@ void ClientModel::setupState(QVariantMap _state) QVariantList stateContracts = _state.value("contracts").toList(); QVariantList transactions = _state.value("transactions").toList(); - map accounts; + unordered_map accounts; std::vector userAccounts; for (auto const& b: stateAccounts) @@ -284,7 +284,7 @@ void ClientModel::setupState(QVariantMap _state) executeSequence(transactionSequence, accounts, Secret(_state.value("miner").toMap().value("secret").toString().toStdString())); } -void ClientModel::executeSequence(vector const& _sequence, std::map const& _accounts, Secret const& _miner) +void ClientModel::executeSequence(vector const& _sequence, std::unordered_map const& _accounts, Secret const& _miner) { if (m_running) { @@ -551,7 +551,7 @@ QVariant ClientModel::formatValue(SolidityType const& _type, u256 const& _value) return res; } -QVariant ClientModel::formatStorageValue(SolidityType const& _type, map const& _storage, unsigned _offset, u256 const& _slot) +QVariant ClientModel::formatStorageValue(SolidityType const& _type, unordered_map const& _storage, unsigned _offset, u256 const& _slot) { u256 slot = _slot; QVariantList values; diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 91b66c76c..b88ae8511 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -220,14 +220,14 @@ private: RecordLogEntry* lastBlock() const; QVariantMap contractAddresses() const; QVariantList gasCosts() const; - void executeSequence(std::vector const& _sequence, std::map const& _accounts, Secret const& _miner); + void executeSequence(std::vector const& _sequence, std::unordered_map const& _accounts, Secret const& _miner); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void onNewTransaction(); void onStateReset(); void showDebuggerForTransaction(ExecutionResult const& _t); QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); - QVariant formatStorageValue(SolidityType const& _type, std::map const& _storage, unsigned _offset, dev::u256 const& _slot); + QVariant formatStorageValue(SolidityType const& _type, std::unordered_map const& _storage, unsigned _offset, dev::u256 const& _slot); std::atomic m_running; std::atomic m_mining; diff --git a/mix/MachineStates.h b/mix/MachineStates.h index afd2b990a..2a88d83bf 100644 --- a/mix/MachineStates.h +++ b/mix/MachineStates.h @@ -50,7 +50,7 @@ namespace mix dev::u256s stack; dev::bytes memory; dev::bigint gasCost; - std::map storage; + std::unordered_map storage; std::vector levels; unsigned codeIndex; unsigned dataIndex; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index b1d8f889e..1f309c5af 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -69,14 +69,14 @@ bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) MixClient::MixClient(std::string const& _dbPath): m_dbPath(_dbPath) { - resetState(std::map()); + resetState(std::unordered_map()); } MixClient::~MixClient() { } -void MixClient::resetState(std::map const& _accounts, Secret const& _miner) +void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { WriteGuard l(x_state); Guard fl(x_filtersWatches); diff --git a/mix/MixClient.h b/mix/MixClient.h index 182e333c2..99637720a 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -48,7 +48,7 @@ public: MixClient(std::string const& _dbPath); virtual ~MixClient(); /// Reset state to the empty state with given balance. - void resetState(std::map const& _accounts, Secret const& _miner = Secret()); + void resetState(std::unordered_map const& _accounts, Secret const& _miner = Secret()); void mine(); ExecutionResult lastExecution() const; ExecutionResult execution(unsigned _index) const; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 144a1a286..96e11e02c 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -305,7 +305,7 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta if (addressOptions.m_bHasStorage) { - map stateStorage = _statePost.storage(a.first); + unordered_map stateStorage = _statePost.storage(a.first); for (auto const& s: _stateExpect.storage(a.first)) CHECK(stateStorage[s.first] == s.second, "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(stateStorage[s.first]) << ", expected [" << s.first << "] = " << toHex(s.second)); diff --git a/test/fuzzTesting/checkRandomStateTest.cpp b/test/fuzzTesting/checkRandomStateTest.cpp index 719798620..01366cd4d 100644 --- a/test/fuzzTesting/checkRandomStateTest.cpp +++ b/test/fuzzTesting/checkRandomStateTest.cpp @@ -173,7 +173,7 @@ bool doStateTest(mValue& _v) } //checkStorage(importer.m_statePost.storage(expectedAddr), theState.storage(expectedAddr), expectedAddr); - map _resultStore = theState.storage(expectedAddr); + unordered_map _resultStore = theState.storage(expectedAddr); for (auto&& expectedStorePair : importer.m_statePost.storage(expectedAddr)) { diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index 93f7498b8..b682056ee 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -99,7 +99,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) ImportTest::checkExpectedState(importer.m_statePost, theState); auto expectedAddrs = importer.m_statePost.addresses(); auto resultAddrs = theState.addresses(); - checkAddresses >(expectedAddrs, resultAddrs); + checkAddresses(expectedAddrs, resultAddrs); #endif BOOST_CHECK_MESSAGE(theState.rootHash() == h256(o["postStateRoot"].get_str()), "wrong post state root"); } From de3ff170c8c137ec0d5486f39adf3a41b7ab6098 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 7 May 2015 17:40:31 +0200 Subject: [PATCH 45/87] use boost hash function for FixedHash, asio adress. Style fixes --- libdevcore/FixedHash.h | 42 +++--------------------------------------- libdevcrypto/Common.h | 2 +- libp2p/Common.h | 4 ++-- libp2p/NodeTable.cpp | 6 +++--- 4 files changed, 9 insertions(+), 45 deletions(-) diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 5ba96b9a8..60c9acad8 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -150,7 +150,7 @@ public: struct hash { /// Make a hash of the object's data. - size_t operator()(FixedHash const& value) const; + size_t operator()(FixedHash const& _value) const { return boost::hash_range(_value.m_data.cbegin(), _value.m_data.cend()); } }; template inline FixedHash& shiftBloom(FixedHash const& _h) @@ -208,47 +208,11 @@ template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) co return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]); } -/// Fast std::hash compatible hash function object for h64. -template<> inline size_t FixedHash<8>::hash::operator()(FixedHash<8> const& value) const -{ - const uint64_t*data = (const uint64_t*)value.data(); - return (size_t)(*data); -} - -/// Fast std::hash compatible hash function object for h160. -template<> inline size_t FixedHash<20>::hash::operator()(FixedHash<20> const& value) const -{ - const uint64_t*data = (const uint64_t*)value.data(); - uint64_t hash = data[0]; - hash ^= data[1]; - hash ^= ((const uint32_t*)value.data())[4]; - return (size_t)hash; -} - /// Fast std::hash compatible hash function object for h256. template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const { - const uint64_t*data = (const uint64_t*)value.data(); - uint64_t hash = data[0]; - hash ^= data[1]; - hash ^= data[2]; - hash ^= data[3]; - return (size_t)hash; -} - -/// Fast std::hash compatible hash function object for h512. -template<> inline size_t FixedHash<64>::hash::operator()(FixedHash<64> const& value) const -{ - const uint64_t*data = (const uint64_t*)value.data(); - uint64_t hash = data[0]; - hash ^= data[1]; - hash ^= data[2]; - hash ^= data[3]; - hash ^= data[4]; - hash ^= data[5]; - hash ^= data[6]; - hash ^= data[7]; - return (size_t)hash; + uint64_t const* data = reinterpret_cast(value.data()); + return boost::hash_range(data, data + 4); } /// Stream I/O for the FixedHash class. diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index b854e76a3..d5d44b6f6 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -68,7 +68,7 @@ extern Address ZeroAddress; /// A vector of Ethereum addresses. using Addresses = h160s; -/// A hash table of Ethereum addresses. +/// A hash set of Ethereum addresses. using AddressHash = std::unordered_set; /// A vector of secrets. diff --git a/libp2p/Common.h b/libp2p/Common.h index 96b8b9683..56121aedc 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -213,14 +213,14 @@ template <> struct hash size_t operator()(bi::address const& _a) const { if (_a.is_v4()) - return _a.to_v4().to_ulong(); + return std::hash()(_a.to_v4().to_ulong()); if (_a.is_v6()) { auto const& range = _a.to_v6().to_bytes(); return boost::hash_range(range.begin(), range.end()); } if (_a.is_unspecified()) - return static_cast(0x3487194039229152ul); // Some random value + return static_cast(0x3487194039229152ul); // Chosen by fair dice roll, guaranteed to be random return std::hash()(_a.to_string()); } }; diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 7a68cae10..f0b8d148c 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -293,9 +293,9 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) } vector> ret; - for (auto n: found) - if (n.second->endpoint.isAllowed()) - ret.push_back(n.second); + for (auto n: found) + if (n.second->endpoint.isAllowed()) + ret.push_back(n.second); return move(ret); } From 9e13963d5f34439da1a2c459dd0091257a1b57df Mon Sep 17 00:00:00 2001 From: winsvega Date: Mon, 27 Apr 2015 14:38:32 +0300 Subject: [PATCH 46/87] Total Difficulty test --- test/libethereum/blockchain.cpp | 320 +++++++++++++++++++------------- 1 file changed, 195 insertions(+), 125 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 954e65c8a..323002b9e 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -56,18 +56,23 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); - TransientDirectory td_stateDB; TransientDirectory td_stateDB_tmp; - State state(State::openDB(td_stateDB.path()), BaseState::Empty, biGenesisBlock.coinbaseAddress); - State stateTemp(State::openDB(td_stateDB_tmp.path()), BaseState::Empty, biGenesisBlock.coinbaseAddress); - importer.importState(o["pre"].get_obj(), state); - o["pre"] = fillJsonWithState(state); - state.commit(); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + + //Imported blocks from the start + typedef std::vector uncleList; + typedef std::pair blockSet; + std::vector blockRLPs; + + importer.importState(o["pre"].get_obj(), trueState); + o["pre"] = fillJsonWithState(trueState); + trueState.commit(); + if (_fillin) - biGenesisBlock.stateRoot = state.rootHash(); + biGenesisBlock.stateRoot = trueState.rootHash(); else - BOOST_CHECK_MESSAGE(biGenesisBlock.stateRoot == state.rootHash(), "root hash does not match"); + BOOST_CHECK_MESSAGE(biGenesisBlock.stateRoot == trueState.rootHash(), "root hash does not match"); if (_fillin) { @@ -83,20 +88,55 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) biGenesisBlock.verifyInternals(&rlpGenesisBlock.out()); o["genesisRLP"] = toHex(rlpGenesisBlock.out(), 2, HexPrefix::Add); - // construct blockchain + // construct true blockchain TransientDirectory td; - BlockChain bc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill); + BlockChain trueBc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill); if (_fillin) { BOOST_REQUIRE(o.count("blocks")); mArray blArray; + + blockSet genesis; + genesis.first = rlpGenesisBlock.out(); + genesis.second = uncleList(); + blockRLPs.push_back(genesis); vector vBiBlocks; vBiBlocks.push_back(biGenesisBlock); + + size_t importBlockNumber; for (auto const& bl: o["blocks"].get_array()) { - stateTemp = state; mObject blObj = bl.get_obj(); + BOOST_REQUIRE(blObj.count("blocknumber")); + + + //each time construct a new blockchain up to importBlockNumber (to generate next block header) + vBiBlocks.clear(); + vBiBlocks.push_back(biGenesisBlock); + + TransientDirectory td_stateDB, td_bc; + BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + importer.importState(o["pre"].get_obj(), state); + state.commit(); + + importBlockNumber = std::max((int)toInt(blObj["blocknumber"]), 1); + for (size_t i = 1; i < importBlockNumber; i++) //0 block is genesis + { + BlockQueue uncleQueue; + uncleList uncles = blockRLPs.at(i).second; + for (size_t j = 0; j < uncles.size(); j++) + uncleQueue.import(&uncles.at(j), bc); + + const bytes block = blockRLPs.at(i).first; + bc.sync(uncleQueue, state.db(), 4); + bc.attemptImport(block, state.db()); + vBiBlocks.push_back(BlockInfo(block)); + + state.sync(bc); + //vBiBlocks.push_back(state.info()); + } // get txs TransactionQueue txs; @@ -115,6 +155,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks); BlockQueue uncleBlockQueue; + uncleList uncleBlockQueueList; cnote << "import uncle in blockQueue"; for (size_t i = 0; i < vBiUncles.size(); i++) { @@ -122,6 +163,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) try { uncleBlockQueue.import(&uncle.out(), bc); + uncleBlockQueueList.push_back(uncle.out()); } catch(...) { @@ -205,6 +247,24 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) bc.import(block2.out(), state.db()); state.sync(bc); state.commit(); + + //there we get new blockchain status in state which could have more difficulty than we have in trueState + //attempt to import new block to the true blockchain + trueBc.sync(uncleBlockQueue, trueState.db(), 4); + trueBc.attemptImport(state.blockData(), trueState.db()); + trueState.sync(trueBc); + + blockSet newBlock; + newBlock.first = state.blockData(); + newBlock.second = uncleBlockQueueList; + if (importBlockNumber < blockRLPs.size()) + { + //make new correct history of imported blocks + blockRLPs[importBlockNumber] = newBlock; + for (size_t i = importBlockNumber+1; i < blockRLPs.size(); i++) + blockRLPs.pop_back(); + } + else blockRLPs.push_back(newBlock); } // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given catch (...) @@ -213,7 +273,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blObj.erase(blObj.find("blockHeader")); blObj.erase(blObj.find("uncleHeaders")); blObj.erase(blObj.find("transactions")); - state = stateTemp; //revert state as if it was before executing this block } blArray.push_back(blObj); this_thread::sleep_for(chrono::seconds(1)); @@ -224,14 +283,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) stateOptionsMap expectStateMap; State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); - ImportTest::checkExpectedState(stateExpect, state, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); + ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); } o["blocks"] = blArray; - o["postState"] = fillJsonWithState(state); + o["postState"] = fillJsonWithState(trueState); - //make all values hex + //make all values hex in pre section State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); @@ -241,14 +300,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { for (auto const& bl: o["blocks"].get_array()) { + bool importedAndNotBest = false; mObject blObj = bl.get_obj(); bytes blockRLP; try { - state.sync(bc); + trueState.sync(trueBc); blockRLP = importByteArray(blObj["rlp"].get_str()); - bc.import(blockRLP, state.db()); - state.sync(bc); + trueBc.import(blockRLP, trueState.db()); + if (trueBc.info() != BlockInfo(blockRLP)) + importedAndNotBest = true; + trueState.sync(trueBc); } // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given catch (Exception const& _e) @@ -284,123 +346,126 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader); blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce); - BlockInfo blockFromRlp = bc.info(); - - //Check the fields restored from RLP to original fields - BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixHash == blockFromRlp.mixHash, "mixHash in given RLP not matching the block mixHash!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); - - BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); - - //Check transaction list - - Transactions txsFromField; + BlockInfo blockFromRlp = trueBc.info(); - for (auto const& txObj: blObj["transactions"].get_array()) + if (!importedAndNotBest) { - mObject tx = txObj.get_obj(); - - BOOST_REQUIRE(tx.count("nonce")); - BOOST_REQUIRE(tx.count("gasPrice")); - BOOST_REQUIRE(tx.count("gasLimit")); - BOOST_REQUIRE(tx.count("to")); - BOOST_REQUIRE(tx.count("value")); - BOOST_REQUIRE(tx.count("v")); - BOOST_REQUIRE(tx.count("r")); - BOOST_REQUIRE(tx.count("s")); - BOOST_REQUIRE(tx.count("data")); - - try - { - Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckTransaction::Everything); - txsFromField.push_back(t); - } - catch (Exception const& _e) + //Check the fields restored from RLP to original fields + BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixHash == blockFromRlp.mixHash, "mixHash in given RLP not matching the block mixHash!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); + + BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); + + //Check transaction list + + Transactions txsFromField; + + for (auto const& txObj: blObj["transactions"].get_array()) { - BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e)); + mObject tx = txObj.get_obj(); + + BOOST_REQUIRE(tx.count("nonce")); + BOOST_REQUIRE(tx.count("gasPrice")); + BOOST_REQUIRE(tx.count("gasLimit")); + BOOST_REQUIRE(tx.count("to")); + BOOST_REQUIRE(tx.count("value")); + BOOST_REQUIRE(tx.count("v")); + BOOST_REQUIRE(tx.count("r")); + BOOST_REQUIRE(tx.count("s")); + BOOST_REQUIRE(tx.count("data")); + + try + { + Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckTransaction::Everything); + txsFromField.push_back(t); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e)); + } + catch (exception const& _e) + { + cnote << _e.what(); + } } - catch (exception const& _e) + + Transactions txsFromRlp; + RLP root(blockRLP); + for (auto const& tr: root[1]) { - cnote << _e.what(); + Transaction tx(tr.data(), CheckTransaction::Everything); + txsFromRlp.push_back(tx); } - } - Transactions txsFromRlp; - RLP root(blockRLP); - for (auto const& tr: root[1]) - { - Transaction tx(tr.data(), CheckTransaction::Everything); - txsFromRlp.push_back(tx); - } + BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match"); - BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match"); - - for (size_t i = 0; i < txsFromField.size(); ++i) - { - BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match"); - - BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions from rlp and transaction from field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match"); - } + for (size_t i = 0; i < txsFromField.size(); ++i) + { + BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match"); + + BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions from rlp and transaction from field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match"); + } - // check uncle list + // check uncle list - // uncles from uncle list field - vector uBlHsFromField; - if (blObj["uncleHeaders"].type() != json_spirit::null_type) - for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array()) - { - mObject uBlH = uBlHeaderObj.get_obj(); - BOOST_REQUIRE(uBlH.size() == 16); - bytes uncleRLP = createBlockRLPFromFields(uBlH); - const RLP c_uRLP(uncleRLP); - BlockInfo uncleBlockHeader; - try + // uncles from uncle list field + vector uBlHsFromField; + if (blObj["uncleHeaders"].type() != json_spirit::null_type) + for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array()) { - uncleBlockHeader.populateFromHeader(c_uRLP); + mObject uBlH = uBlHeaderObj.get_obj(); + BOOST_REQUIRE(uBlH.size() == 16); + bytes uncleRLP = createBlockRLPFromFields(uBlH); + const RLP c_uRLP(uncleRLP); + BlockInfo uncleBlockHeader; + try + { + uncleBlockHeader.populateFromHeader(c_uRLP); + } + catch(...) + { + BOOST_ERROR("invalid uncle header"); + } + uBlHsFromField.push_back(uncleBlockHeader); } - catch(...) - { - BOOST_ERROR("invalid uncle header"); - } - uBlHsFromField.push_back(uncleBlockHeader); - } - // uncles from block RLP - vector uBlHsFromRlp; - for (auto const& uRLP: root[2]) - { - BlockInfo uBl; - uBl.populateFromHeader(uRLP); - uBlHsFromRlp.push_back(uBl); - } + // uncles from block RLP + vector uBlHsFromRlp; + for (auto const& uRLP: root[2]) + { + BlockInfo uBl; + uBl.populateFromHeader(uRLP); + uBlHsFromRlp.push_back(uBl); + } - BOOST_REQUIRE_EQUAL(uBlHsFromField.size(), uBlHsFromRlp.size()); + BOOST_REQUIRE_EQUAL(uBlHsFromField.size(), uBlHsFromRlp.size()); - for (size_t i = 0; i < uBlHsFromField.size(); ++i) - BOOST_CHECK_MESSAGE(uBlHsFromField[i] == uBlHsFromRlp[i], "block header in rlp and in field do not match"); + for (size_t i = 0; i < uBlHsFromField.size(); ++i) + BOOST_CHECK_MESSAGE(uBlHsFromField[i] == uBlHsFromRlp[i], "block header in rlp and in field do not match"); + } } } } @@ -635,11 +700,11 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) _o["transactionsTrie"] = toString(_bi.transactionsRoot); _o["receiptTrie"] = toString(_bi.receiptsRoot); _o["bloom"] = toString(_bi.logBloom); - _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); - _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); - _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); + _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add); + _o["number"] = toCompactHex(_bi.number, HexPrefix::Add); + _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add); + _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add); _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); @@ -669,6 +734,11 @@ BOOST_AUTO_TEST_CASE(bcForkBlockTest) dev::test::executeTests("bcForkBlockTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); } +BOOST_AUTO_TEST_CASE(bcTotalDifficultyTest) +{ + dev::test::executeTests("bcTotalDifficultyTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); +} + BOOST_AUTO_TEST_CASE(bcInvalidRLPTest) { dev::test::executeTests("bcInvalidRLPTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); From b0d1cbb8a1a940776f5d812f1c4ec13e90ef6d8c Mon Sep 17 00:00:00 2001 From: winsvega Date: Mon, 27 Apr 2015 21:07:55 +0300 Subject: [PATCH 47/87] total difficulty --- libethcore/BlockInfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 24fc1cb65..431f98bf8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -212,9 +212,10 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const if (transactionsRoot != t.root())*/ auto txList = root[1]; auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); }); + cnote << "expect trroot " << toString(expectedRoot); if (transactionsRoot != expectedRoot) BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot)); - + cnote << "expect uncleh " << toString(sha3(root[2].data())); if (sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } From 811103ef881cb23ff0ccfa05f0dbc0da8fff7cb3 Mon Sep 17 00:00:00 2001 From: winsvega Date: Tue, 28 Apr 2015 17:08:41 +0300 Subject: [PATCH 48/87] Total Difficulty: uncle blocks --- libethereum/State.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 83a78e1e8..259fe70c0 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -610,6 +610,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement if (receiptsTrie.root() != m_currentBlock.receiptsRoot) { cwarn << "Bad receipts state root."; + cwarn << "Expected: " << toString(receiptsTrie.root()) << " received: " << toString(m_currentBlock.receiptsRoot); cwarn << "Block:" << toHex(_block); cwarn << "Block RLP:" << rlp; cwarn << "Calculated: " << receiptsTrie.root(); From 649c4761686dd7139c7c2914f8f1db9624be68e4 Mon Sep 17 00:00:00 2001 From: winsvega Date: Tue, 28 Apr 2015 17:20:33 +0300 Subject: [PATCH 49/87] Total Difficulty: merge revert --- test/libethereum/blockchain.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 323002b9e..30bdf62c9 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -700,11 +700,11 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) _o["transactionsTrie"] = toString(_bi.transactionsRoot); _o["receiptTrie"] = toString(_bi.receiptsRoot); _o["bloom"] = toString(_bi.logBloom); - _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add); - _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add); - _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add); + _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); + _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); + _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); From ee71caac67ffdd2842f699aac126bc157de79d55 Mon Sep 17 00:00:00 2001 From: winsvega Date: Tue, 28 Apr 2015 17:43:29 +0300 Subject: [PATCH 50/87] Total Difficulty: blockweight test filler --- test/bcBlockWeightTestFiller.json | 106 ++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 test/bcBlockWeightTestFiller.json diff --git a/test/bcBlockWeightTestFiller.json b/test/bcBlockWeightTestFiller.json new file mode 100644 index 000000000..62158032e --- /dev/null +++ b/test/bcBlockWeightTestFiller.json @@ -0,0 +1,106 @@ +{ +"diffTooHigh" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + { + "overwriteAndRedoPoW" : "difficulty", + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "acde5374fce5edbc8e2a8697c15331677e6ebf0b", + "difficulty" : "131073", + "extraData" : "0x", + "gasLimit" : "4141592", + "gasUsed" : "150000", + "hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04", + "mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770", + "nonce" : "18a524c1790fa83b", + "number" : "2", + "parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd", + "timestamp" : "142813170", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } + ] + } + ] + } +} From b635a4929b461f784cd457851e2c6fc5beda683e Mon Sep 17 00:00:00 2001 From: winsvega Date: Tue, 28 Apr 2015 17:47:25 +0300 Subject: [PATCH 51/87] Total Difficulty: test filler --- .../bcTotalDifficultyTestFiller.json} | 63 ++++++++++++------- 1 file changed, 39 insertions(+), 24 deletions(-) rename test/{bcBlockWeightTestFiller.json => libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json} (71%) diff --git a/test/bcBlockWeightTestFiller.json b/test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json similarity index 71% rename from test/bcBlockWeightTestFiller.json rename to test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json index 62158032e..cf1a85e7b 100644 --- a/test/bcBlockWeightTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json @@ -1,5 +1,5 @@ { -"diffTooHigh" : { + "newMaxDifficulty" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", @@ -17,15 +17,12 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "expect" : { + "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "30" + "balance" : "40" }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "nonce" : "3" - }, - "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "1312500000000000000" } }, "pre" : { @@ -38,6 +35,7 @@ }, "blocks" : [ { + "blocknumber" : "1", "transactions" : [ { "data" : "", @@ -53,6 +51,7 @@ ] }, { + "blocknumber" : "2", "transactions" : [ { "data" : "", @@ -68,6 +67,7 @@ ] }, { + "blocknumber" : "3", "transactions" : [ { "data" : "", @@ -76,30 +76,45 @@ "nonce" : "2", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" + "value" : "20" } ], "uncleHeaders" : [ { - "overwriteAndRedoPoW" : "difficulty", - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "acde5374fce5edbc8e2a8697c15331677e6ebf0b", - "difficulty" : "131073", - "extraData" : "0x", - "gasLimit" : "4141592", - "gasUsed" : "150000", - "hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04", - "mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770", - "nonce" : "18a524c1790fa83b", - "number" : "2", - "parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae", - "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd", - "timestamp" : "142813170", - "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020040", + "extraData" : "0x", + "gasLimit" : "0x2fefd8", + "gasUsed" : "0x5208", + "hash" : "9168fbfb2e3fbedfdb9eac6f73b6d7c9323c957fc3406f27a2f44983f0e5dd43", + "mixHash" : "d56ea25bfefc68484759c3dd934030624308b7ab02bb20aee17852aff72f1397", + "nonce" : "6e7970f59660cbd7", + "number" : "0x02", + "parentHash" : "b7afc3043361f44fd15c0f8df8ebab8284d01c8f79fb47b6fc75eec98b4b4683", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "a2a5e3d96e902272adb58e90c364f7b92684c539e0ded77356cf33d966f917fe", + "timestamp" : "0x553e25de", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" } ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] } ] } From 1177f971d9d4b1f29b545e4ff0fc6aa127665567 Mon Sep 17 00:00:00 2001 From: winsvega Date: Wed, 29 Apr 2015 18:56:28 +0300 Subject: [PATCH 52/87] Total Difficulty: new tests --- .../bcTotalDifficultyTestFiller.json | 1485 ++++++++++++++++- test/libethereum/blockchain.cpp | 32 +- 2 files changed, 1497 insertions(+), 20 deletions(-) diff --git a/test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json b/test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json index cf1a85e7b..1acaa23e9 100644 --- a/test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json @@ -1,5 +1,5 @@ { - "newMaxDifficulty" : { + "sideChainWithMoreTransactions" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", @@ -21,6 +21,940 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "40" }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "4" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "blocknumber" : "1", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "2", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31059", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x3453454", + "gasLimit" : "31509", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + }, + { + "data" : "", + "gasLimit" : "31509", + "gasPrice" : "1", + "nonce" : "4", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "195e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "lotsOfBranchesOverrideAtTheEnd" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "820" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "4" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "blocknumber" : "1", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "2", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314134359", + "gasPrice" : "1343", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x34235435346", + "gasLimit" : "314143359", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "3331", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "200" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x44634634", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "200" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31059", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x3453454", + "gasLimit" : "31509", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "795e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "1000" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31400", + "gasPrice" : "100000000", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "400" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "10", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "400" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "5", + "transactions" : [ + { + "data" : "0x44634634", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "400" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "lotsOfBranchesOverrideAtTheMiddle" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "420" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "4" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "blocknumber" : "1", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "2", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314134359", + "gasPrice" : "1343", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x34235435346", + "gasLimit" : "314143359", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "3331", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "200" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x44634634", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "200" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "5", + "transactions" : [ + { + "data" : "0x44634634", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "200" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31059", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x3453454", + "gasLimit" : "31509", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "795e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "1000" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31400", + "gasPrice" : "100000000", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "400" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "10", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "400" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "lotsOfBranches" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "40" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "4" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "blocknumber" : "1", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "2", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314134359", + "gasPrice" : "1343", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x34235435346", + "gasLimit" : "314143359", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "3331", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "200" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x44634634", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "200" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31059", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "0x3453454", + "gasLimit" : "31509", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "300" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "795e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "1000" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31400", + "gasPrice" : "100000000", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "400" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "10", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "400" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "lotsOfLeafs" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1" + }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "nonce" : "3" } @@ -44,7 +978,412 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" + "value" : "0" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "2", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "1" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314134359", + "gasPrice" : "1343", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "2" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "0x34235435346", + "gasLimit" : "314143359", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "3" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "3331", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "4" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "0x44634634", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31059", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "6" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "0x3453454", + "gasLimit" : "31509", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "7" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "795e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "9" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "31400", + "gasPrice" : "100000000000", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "10", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "11" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "sideChainWithNewMaxDifficultyStartingFromBlock3AfterBlock4" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "45" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "5" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "blocknumber" : "1", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "1" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "2", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "3" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "7" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "11" + } + ], + "uncleHeaders" : [ + { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020040", + "extraData" : "0x", + "gasLimit" : "0x2fefd8", + "gasUsed" : "0x5208", + "hash" : "9168fbfb2e3fbedfdb9eac6f73b6d7c9323c957fc3406f27a2f44983f0e5dd43", + "mixHash" : "d56ea25bfefc68484759c3dd934030624308b7ab02bb20aee17852aff72f1397", + "nonce" : "6e7970f59660cbd7", + "number" : "0x02", + "parentHash" : "b7afc3043361f44fd15c0f8df8ebab8284d01c8f79fb47b6fc75eec98b4b4683", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "a2a5e3d96e902272adb58e90c364f7b92684c539e0ded77356cf33d966f917fe", + "timestamp" : "0x553e25de", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "13" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "5", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "4", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "17" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "uncleBlockAtBlock3afterBlock4" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "16" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "4" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "blocknumber" : "1", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "1" } ], "uncleHeaders" : [ @@ -60,7 +1399,39 @@ "nonce" : "1", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" + "value" : "3" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "4", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "3", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "7" } ], "uncleHeaders" : [ @@ -76,7 +1447,7 @@ "nonce" : "2", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "20" + "value" : "11" } ], "uncleHeaders" : [ @@ -99,6 +1470,76 @@ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" } ] + } + ] + }, + + "uncleBlockAtBlock3AfterBlock3" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "9" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "blocknumber" : "1", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "1" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "2", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "3" + } + ], + "uncleHeaders" : [ + ] }, { "blocknumber" : "3", @@ -110,10 +1551,44 @@ "nonce" : "2", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" + "value" : "5" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "3", + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "7" } ], "uncleHeaders" : [ + { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020040", + "extraData" : "0x", + "gasLimit" : "0x2fefd8", + "gasUsed" : "0x5208", + "hash" : "9168fbfb2e3fbedfdb9eac6f73b6d7c9323c957fc3406f27a2f44983f0e5dd43", + "mixHash" : "d56ea25bfefc68484759c3dd934030624308b7ab02bb20aee17852aff72f1397", + "nonce" : "6e7970f59660cbd7", + "number" : "0x02", + "parentHash" : "b7afc3043361f44fd15c0f8df8ebab8284d01c8f79fb47b6fc75eec98b4b4683", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "a2a5e3d96e902272adb58e90c364f7b92684c539e0ded77356cf33d966f917fe", + "timestamp" : "0x553e25de", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } ] } ] diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 30bdf62c9..0a8de0392 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -62,7 +62,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) //Imported blocks from the start typedef std::vector uncleList; typedef std::pair blockSet; - std::vector blockRLPs; + std::vector blockSets; importer.importState(o["pre"].get_obj(), trueState); o["pre"] = fillJsonWithState(trueState); @@ -100,7 +100,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blockSet genesis; genesis.first = rlpGenesisBlock.out(); genesis.second = uncleList(); - blockRLPs.push_back(genesis); + blockSets.push_back(genesis); vector vBiBlocks; vBiBlocks.push_back(biGenesisBlock); @@ -110,7 +110,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) mObject blObj = bl.get_obj(); BOOST_REQUIRE(blObj.count("blocknumber")); - //each time construct a new blockchain up to importBlockNumber (to generate next block header) vBiBlocks.clear(); vBiBlocks.push_back(biGenesisBlock); @@ -125,11 +124,11 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) for (size_t i = 1; i < importBlockNumber; i++) //0 block is genesis { BlockQueue uncleQueue; - uncleList uncles = blockRLPs.at(i).second; + uncleList uncles = blockSets.at(i).second; for (size_t j = 0; j < uncles.size(); j++) uncleQueue.import(&uncles.at(j), bc); - const bytes block = blockRLPs.at(i).first; + const bytes block = blockSets.at(i).first; bc.sync(uncleQueue, state.db(), 4); bc.attemptImport(block, state.db()); vBiBlocks.push_back(BlockInfo(block)); @@ -257,14 +256,15 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blockSet newBlock; newBlock.first = state.blockData(); newBlock.second = uncleBlockQueueList; - if (importBlockNumber < blockRLPs.size()) + if (importBlockNumber < blockSets.size()) { //make new correct history of imported blocks - blockRLPs[importBlockNumber] = newBlock; - for (size_t i = importBlockNumber+1; i < blockRLPs.size(); i++) - blockRLPs.pop_back(); + blockSets[importBlockNumber] = newBlock; + for (size_t i = importBlockNumber+1; i < blockSets.size(); i++) + blockSets.pop_back(); } - else blockRLPs.push_back(newBlock); + else + blockSets.push_back(newBlock); } // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given catch (...) @@ -289,6 +289,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["blocks"] = blArray; o["postState"] = fillJsonWithState(trueState); + o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); @@ -300,7 +301,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { for (auto const& bl: o["blocks"].get_array()) { - bool importedAndNotBest = false; + bool importedAndBest = true; mObject blObj = bl.get_obj(); bytes blockRLP; try @@ -309,7 +310,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blockRLP = importByteArray(blObj["rlp"].get_str()); trueBc.import(blockRLP, trueState.db()); if (trueBc.info() != BlockInfo(blockRLP)) - importedAndNotBest = true; + importedAndBest = false; trueState.sync(trueBc); } // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given @@ -348,7 +349,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) BlockInfo blockFromRlp = trueBc.info(); - if (!importedAndNotBest) + if (importedAndBest) { //Check the fields restored from RLP to original fields BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); @@ -465,8 +466,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) for (size_t i = 0; i < uBlHsFromField.size(); ++i) BOOST_CHECK_MESSAGE(uBlHsFromField[i] == uBlHsFromRlp[i], "block header in rlp and in field do not match"); - } - } + }//importedAndBest + }//all blocks } } } @@ -508,6 +509,7 @@ mArray importUncles(mObject const& blObj, vector& vBiUncles, vector 0) + importBlockNumber = std::max((int)toInt(blObj["blocknumber"]), 1); + else + importBlockNumber++; //each time construct a new blockchain up to importBlockNumber (to generate next block header) vBiBlocks.clear(); @@ -120,7 +123,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) importer.importState(o["pre"].get_obj(), state); state.commit(); - importBlockNumber = std::max((int)toInt(blObj["blocknumber"]), 1); for (size_t i = 1; i < importBlockNumber; i++) //0 block is genesis { BlockQueue uncleQueue; @@ -134,7 +136,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) vBiBlocks.push_back(BlockInfo(block)); state.sync(bc); - //vBiBlocks.push_back(state.info()); } // get txs @@ -260,7 +261,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //make new correct history of imported blocks blockSets[importBlockNumber] = newBlock; - for (size_t i = importBlockNumber+1; i < blockSets.size(); i++) + for (size_t i = importBlockNumber + 1; i < blockSets.size(); i++) blockSets.pop_back(); } else From 8413971fac57a556480fc5f7c23a5e66a25ec25b Mon Sep 17 00:00:00 2001 From: winsvega Date: Tue, 5 May 2015 18:25:51 +0300 Subject: [PATCH 54/87] Total Difficulty: lastblockhash check --- test/libethereum/blockchain.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index f690d6a55..ac26e50f7 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -68,7 +68,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["pre"] = fillJsonWithState(trueState); trueState.commit(); - if (_fillin) biGenesisBlock.stateRoot = trueState.rootHash(); else @@ -469,6 +468,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK_MESSAGE(uBlHsFromField[i] == uBlHsFromRlp[i], "block header in rlp and in field do not match"); }//importedAndBest }//all blocks + + BOOST_REQUIRE(o.count("lastblockhash") > 0); + BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"], "last block hash of constructed blockchain does not match provided hash of the last block!"); } } } From 1a5d03c2acaf06cfaacc8114eee893e47f41abf7 Mon Sep 17 00:00:00 2001 From: winsvega Date: Tue, 5 May 2015 22:11:37 +0300 Subject: [PATCH 55/87] Total Difficulty: bug fix --- test/libethereum/blockchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index ac26e50f7..d9dc6e8b3 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -470,7 +470,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) }//all blocks BOOST_REQUIRE(o.count("lastblockhash") > 0); - BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"], "last block hash of constructed blockchain does not match provided hash of the last block!"); + BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"].get_str(), "last block hash of constructed blockchain does not match provided hash of the last block!"); } } } From 69eaeb48305283fae9360a2cb9b3ff6832c6ea94 Mon Sep 17 00:00:00 2001 From: winsvega Date: Thu, 7 May 2015 19:59:37 +0300 Subject: [PATCH 56/87] Total Difficulty: last block hash fix --- test/libethereum/blockchain.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index d9dc6e8b3..c5ac936fe 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -48,9 +48,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { for (auto& i: _v.get_obj()) { - cerr << i.first << endl; mObject& o = i.second.get_obj(); + if (test::Options::get().singleTest && test::Options::get().singleTestName != i.first) + { + o.clear(); + continue; + } + cerr << i.first << endl; BOOST_REQUIRE(o.count("genesisBlockHeader")); BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj()); @@ -250,11 +255,11 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) //there we get new blockchain status in state which could have more difficulty than we have in trueState //attempt to import new block to the true blockchain trueBc.sync(uncleBlockQueue, trueState.db(), 4); - trueBc.attemptImport(state.blockData(), trueState.db()); + trueBc.attemptImport(block2.out(), trueState.db()); trueState.sync(trueBc); blockSet newBlock; - newBlock.first = state.blockData(); + newBlock.first = block2.out(); newBlock.second = uncleBlockQueueList; if (importBlockNumber < blockSets.size()) { @@ -306,8 +311,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) bytes blockRLP; try { - trueState.sync(trueBc); blockRLP = importByteArray(blObj["rlp"].get_str()); + trueState.sync(trueBc); trueBc.import(blockRLP, trueState.db()); if (trueBc.info() != BlockInfo(blockRLP)) importedAndBest = false; @@ -470,7 +475,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) }//all blocks BOOST_REQUIRE(o.count("lastblockhash") > 0); - BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"].get_str(), "last block hash of constructed blockchain does not match provided hash of the last block!"); + BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"].get_str(), + "Boost check: " + i.first + " lastblockhash does not match " + toString(trueBc.info().hash()) + " expected: " + o["lastblockhash"].get_str()); } } } From cd64adc5414d190c142fffb6f88de090709d09e4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 8 May 2015 11:13:36 +0200 Subject: [PATCH 57/87] Basic key manager. --- exp/main.cpp | 86 ++++++++++++++++++++++++++++-------- libdevcore/FixedHash.h | 3 ++ libdevcrypto/Common.cpp | 28 +++++------- libdevcrypto/Common.h | 8 ++-- libdevcrypto/CryptoPP.cpp | 5 +-- test/libdevcrypto/crypto.cpp | 11 +++-- 6 files changed, 93 insertions(+), 48 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 4fff5b63a..5a57c091e 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -65,6 +65,7 @@ namespace fs = boost::filesystem; #if 1 inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); } +inline std::string toUUID(h128 const& _uuid) { std::string ret = toHex(_uuid.ref()); for (unsigned i: {20, 16, 12, 8}) ret.insert(ret.begin() + i, '-'); return ret; } class KeyManager: public Worker { @@ -74,31 +75,48 @@ public: Secret secret(h128 const& _uuid, function const& _pass) { - auto rit = m_ready.find(_uuid); - if (rit != m_ready.end()) + auto rit = m_cached.find(_uuid); + if (rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); if (it == m_keys.end()) return Secret(); Secret ret(decrypt(it->second, _pass())); if (ret) - m_ready[_uuid] = ret; + m_cached[_uuid] = ret; return ret; } - h128 create(std::string const& _pass) + h128 import(Secret const& _s, std::string const& _pass) { - auto s = Secret::random(); - h128 r(sha3(s)); - m_ready[r] = s; - m_keys[r] = encrypt(s.asBytes(), _pass); + h128 r(sha3(_s)); + m_cached[r] = _s; + m_keys[r] = encrypt(_s.asBytes(), _pass); + writeKeys(); return r; } + h128 create(std::string const& _pass) + { + return import(Secret::random(), _pass); + } + + void clearCache() const { m_cached.clear(); } + private: void writeKeys(std::string const& _keysPath = getDataDir("web3") + "/keys") { - (void)_keysPath; + fs::path p(_keysPath); + boost::filesystem::create_directories(p); + for (auto const& k: m_keys) + { + std::string uuid = toUUID(k.first); + js::mObject v; + v["crypto"] = k.second; + v["id"] = uuid; + v["version"] = 2; + writeFile((p / uuid).string() + ".json", js::write_string(js::mValue(v), true)); + } } void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys") @@ -126,9 +144,42 @@ private: static js::mValue encrypt(bytes const& _v, std::string const& _pass) { - (void)_v; - (void)_pass; - return js::mValue(); + js::mObject ret; + + // KDF info + unsigned dklen = 16; + unsigned iterations = 262144; + bytes salt = h256::random().asBytes(); + ret["kdf"] = "pbkdf2"; + { + js::mObject params; + params["prf"] = "hmac-sha256"; + params["c"] = (int)iterations; + params["salt"] = toHex(salt); + params["dklen"] = (int)dklen; + ret["kdfparams"] = params; + } + bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen); + + // cipher info + ret["cipher"] = "aes-128-cbc"; + h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + h128 iv = h128::random(); + { + js::mObject params; + params["iv"] = toHex(iv.ref()); + ret["cipherparams"] = params; + } + + // cipher text + bytes cipherText = encryptSymNoAuth(key, iv, &_v); + ret["ciphertext"] = toHex(cipherText); + + // and mac. + h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + ret["mac"] = toHex(mac.ref()); + + return ret; } static bytes decrypt(js::mValue const& _v, std::string const& _pass) @@ -167,32 +218,29 @@ private: } // decrypt - bytes ret; if (o["cipher"].get_str() == "aes-128-cbc") { auto params = o["cipherparams"].get_obj(); h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); h128 iv(params["iv"].get_str()); - decryptSymNoAuth(key, iv, &cipherText, ret); + return decryptSymNoAuth(key, iv, &cipherText); } else { cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported."; return bytes(); } - - return ret; } - mutable std::map m_ready; + mutable std::map m_cached; std::map m_keys; }; int main() { - cdebug << toHex(pbkdf2("password", asBytes("salt"), 1, 20)); KeyManager keyman; - cdebug << "Secret key for 0498f19a-59db-4d54-ac95-33901b4f1870 is " << keyman.secret(fromUUID("0498f19a-59db-4d54-ac95-33901b4f1870"), [](){ return "foo"; }); + auto id = fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0"); + cdebug << "Secret key for " << toUUID(id) << "is" << keyman.secret(id, [](){ return "bar"; }); } #elif 0 diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 2cf81cb77..3d7a830e6 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -113,6 +113,9 @@ public: /// @returns an abridged version of the hash as a user-readable hex string. std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } + /// @returns an abridged version of the hash as a user-readable hex string. + std::string hex() const { return toHex(ref()); } + /// @returns a mutable byte vector_ref to the object's data. bytesRef ref() { return bytesRef(m_data.data(), N); } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index c3133cca7..e4f383a38 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -112,51 +112,47 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) return decrypt(_k, _cipher, o_plain); } -h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher) +std::pair dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain) { h128 iv(Nonce::get()); - return encryptSymNoAuth(_k, _plain, o_cipher, iv); + return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); } -h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv) +bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { - o_cipher.resize(_plain.size()); - const int c_aesKeyLen = 16; SecByteBlock key(_k.data(), c_aesKeyLen); try { CTR_Mode::Encryption e; e.SetKeyWithIV(key, key.size(), _iv.data()); - e.ProcessData(o_cipher.data(), _plain.data(), _plain.size()); - return _iv; + bytes ret(_plain.size()); + e.ProcessData(ret.data(), _plain.data(), _plain.size()); + return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; - o_cipher.resize(0); - return h128(); + return bytes(); } } -bool dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext) +bytes dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { - o_plaintext.resize(_cipher.size()); - const size_t c_aesKeyLen = 16; SecByteBlock key(_k.data(), c_aesKeyLen); try { CTR_Mode::Decryption d; d.SetKeyWithIV(key, key.size(), _iv.data()); - d.ProcessData(o_plaintext.data(), _cipher.data(), _cipher.size()); - return true; + bytes ret(_cipher.size()); + d.ProcessData(ret.data(), _cipher.data(), _cipher.size()); + return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; - o_plaintext.resize(0); - return false; + return bytes(); } } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 3b243d319..48660bb96 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -103,13 +103,13 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); /// Encrypts payload with random IV/ctr using AES128-CTR. -h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher); +std::pair encryptSymNoAuth(h128 const& _k, bytesConstRef _plain); /// Encrypts payload with specified IV/ctr using AES128-CTR. -h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv); - +bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain); + /// Decrypts payload with specified IV/ctr using AES128-CTR. -bool decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext); +bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher); /// Recovers Public key from signed message hash. Public recover(Signature const& _sig, h256 const& _hash); diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index e89857502..b701fed8d 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -78,8 +78,7 @@ void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher) bytes mKey(32); ctx.Final(mKey.data()); - bytes cipherText; - encryptSymNoAuth(h128(eKey), bytesConstRef(&io_cipher), cipherText, h128()); + bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher)); if (cipherText.empty()) return; @@ -139,7 +138,7 @@ bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text) if (mac[i] != msgMac[i]) return false; - decryptSymNoAuth(h128(eKey), iv, cipherNoIV, plain); + plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV); io_text.resize(plain.size()); io_text.swap(plain); diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index 96826bdf9..88ff98965 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -593,15 +593,14 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) // TESTING: send encrypt magic sequence bytes magic {0x22,0x40,0x08,0x91}; bytes magicCipherAndMac; - encryptSymNoAuth(encryptK, &magic, magicCipherAndMac, h128()); + magicCipherAndMac = encryptSymNoAuth(encryptK, h128(), &magic); magicCipherAndMac.resize(magicCipherAndMac.size() + 32); sha3mac(egressMac.ref(), &magic, egressMac.ref()); egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32)); - bytes plaintext; bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32); - decryptSymNoAuth(encryptK, h128(), cipher, plaintext); + bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher); plaintext.resize(magic.size()); BOOST_REQUIRE(plaintext.size() > 0); @@ -615,10 +614,10 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) bytesConstRef msg((byte*)m.data(), m.size()); bytes ciphertext; - auto iv = encryptSymNoAuth(k, msg, ciphertext); + h128 iv; + tie(ciphertext, iv) = encryptSymNoAuth(k, msg); - bytes plaintext; - decryptSymNoAuth(k, iv, &ciphertext, plaintext); + bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext); BOOST_REQUIRE_EQUAL(asString(plaintext), m); } From d24b48853dcd444c2bf0844c967da50e88cf20ee Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 8 May 2015 16:45:23 +0200 Subject: [PATCH 58/87] new abi --- mix/ContractCallDataEncoder.cpp | 18 +++++++++++++++--- mix/ContractCallDataEncoder.h | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 6b29d8b98..9ea1c3510 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -36,6 +36,14 @@ using namespace dev::mix; bytes ContractCallDataEncoder::encodedData() { bytes r(m_encodedData); + size_t headerSize = m_encodedData.size() & ~0x1fUL; //ignore any prefix that is not 32-byte aligned + //apply offsets + for (auto const& p: m_offsetMap) + { + vector_ref offsetRef(r.data() + p.first, 32); + toBigEndian>(p.second + headerSize, offsetRef); //add header size minus signature hash + } + r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end()); return r; } @@ -64,6 +72,9 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& if (_type.dynamicSize) { + bytes empty(32); + size_t sizePos = m_dynamicData.size(); + m_dynamicData.insert(m_dynamicData.end(), empty.begin(), empty.end()); //reserve space for count if (_type.type == SolidityType::Type::Bytes) count = encodeSingleItem(_data.toString(), _type, m_dynamicData); else @@ -72,9 +83,10 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& for (auto const& item: strList) encodeSingleItem(item, _type, m_dynamicData); } - bytes sizeEnc(32); - toBigEndian(count, sizeEnc); - m_encodedData.insert(m_encodedData.end(), sizeEnc.begin(), sizeEnc.end()); + vector_ref sizeRef(m_dynamicData.data() + sizePos, 32); + toBigEndian(count, sizeRef); + m_offsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); + m_encodedData.insert(m_encodedData.end(), empty.begin(), empty.end()); //reserve space for offset } else { diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index cab00dd93..2707845ae 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -73,6 +73,7 @@ private: private: bytes m_encodedData; bytes m_dynamicData; + std::vector> m_offsetMap; }; } From 1a37c58c9e21009556542a0c291bc69dc50d63cc Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 8 May 2015 16:50:04 +0200 Subject: [PATCH 59/87] default gas settings fixed in web3 server --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 94a43871f..3f0566626 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -531,9 +531,9 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json) t.from = m_accounts->getDefaultTransactAccount(); if (t.creation) ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));; - if (!t.gasPrice) + if (t.gasPrice == UndefinedU256) t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow. - if (!t.gas) + if (t.gas == UndefinedU256) t.gas = min(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice); if (m_accounts->isRealAccount(t.from)) @@ -582,9 +582,9 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const& t.from = m_accounts->getDefaultTransactAccount(); // if (!m_accounts->isRealAccount(t.from)) // return ret; - if (!t.gasPrice) + if (t.gasPrice == UndefinedU256) t.gasPrice = 10 * dev::eth::szabo; - if (!t.gas) + if (t.gas == UndefinedU256) t.gas = client()->gasLimitRemaining(); return toJS(client()->call(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice, jsToBlockNumber(_blockNumber), FudgeFactor::Lenient).output); From 37440f3a01df38850dd3046b54ed2f36fad4c566 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 8 May 2015 16:54:39 +0200 Subject: [PATCH 60/87] New ABI encoding for dynamic types. --- libsolidity/Compiler.cpp | 46 +++++++++-------------- test/libsolidity/SolidityCompiler.cpp | 10 ++--- test/libsolidity/SolidityEndToEndTest.cpp | 17 +++++---- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index fb2ab3156..bcd4f9d68 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -206,16 +206,9 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) { - // We do not check the calldata size, everything is zero-padded. - unsigned offset(CompilerUtils::dataStartOffset); + // We do not check the calldata size, everything is zero-paddedd - bigint parameterHeadEnd = offset; - for (TypePointer const& type: _typeParameters) - parameterHeadEnd += type->isDynamicallySized() ? 32 : type->getCalldataEncodedSize(); - solAssert(parameterHeadEnd <= numeric_limits::max(), "Arguments too large."); - - unsigned stackHeightOfPreviousDynamicArgument = 0; - ArrayType const* previousDynamicType = nullptr; + m_context << u256(CompilerUtils::dataStartOffset); for (TypePointer const& type: _typeParameters) { switch (type->getCategory()) @@ -223,34 +216,31 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool case Type::Category::Array: if (type->isDynamicallySized()) { - // put on stack: data_offset length - unsigned newStackHeight = m_context.getStackHeight(); - if (previousDynamicType) - { - // Retrieve data start offset by adding length to start offset of previous dynamic type - unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument; - solAssert(stackDepth <= 16, "Stack too deep."); - m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth); - ArrayUtils(m_context).convertLengthToSize(*previousDynamicType, true); - m_context << eth::Instruction::ADD; - } - else - m_context << u256(parameterHeadEnd); - stackHeightOfPreviousDynamicArgument = newStackHeight; - previousDynamicType = &dynamic_cast(*type); - offset += CompilerUtils(m_context).loadFromMemory(offset, IntegerType(256), !_fromMemory); + // put on stack: data_pointer length + CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory); + // stack: data_offset next_pointer + //@todo once we support nested arrays, this offset needs to be dynamic. + m_context << eth::Instruction::SWAP1 << u256(CompilerUtils::dataStartOffset); + m_context << eth::Instruction::ADD; + // stack: next_pointer data_pointer + // retrieve length + CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); + // stack: next_pointer length data_pointer + m_context << eth::Instruction::SWAP2; } else { - m_context << u256(offset); - offset += type->getCalldataEncodedSize(); + // leave the pointer on the stack + m_context << eth::Instruction::DUP1; + m_context << u256(type->getCalldataEncodedSize()) << eth::Instruction::ADD; } break; default: solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); - offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, true); + CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true); } } + m_context << eth::Instruction::POP; } void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) diff --git a/test/libsolidity/SolidityCompiler.cpp b/test/libsolidity/SolidityCompiler.cpp index 7b0ceedb6..aa83c4650 100644 --- a/test/libsolidity/SolidityCompiler.cpp +++ b/test/libsolidity/SolidityCompiler.cpp @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) "}\n"; bytes code = compileContract(sourceCode); - unsigned boilerplateSize = 70; + unsigned boilerplateSize = 73; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x2, @@ -114,8 +114,8 @@ BOOST_AUTO_TEST_CASE(ifStatement) " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 57; - unsigned boilerplateSize = 70; + unsigned shift = 60; + unsigned boilerplateSize = 73; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), @@ -155,8 +155,8 @@ BOOST_AUTO_TEST_CASE(loops) " function f() { while(true){1;break;2;continue;3;return;4;} }" "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 57; - unsigned boilerplateSize = 70; + unsigned shift = 60; + unsigned boilerplateSize = 73; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x1, diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f168ad454..fd4c83b09 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -2962,12 +2962,13 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments) } )"; compileAndRun(sourceCode); + string innercalldata1 = asString(FixedHash<4>(dev::sha3("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); - bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13); string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3)); bytes calldata = encodeArgs( - 12, u256(innercalldata1.length()), u256(innercalldata2.length()), 13, - innercalldata1, innercalldata2); + 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, + u256(innercalldata1.length()), innercalldata1, + u256(innercalldata2.length()), innercalldata2); BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata) == encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length()))); } @@ -3383,9 +3384,10 @@ BOOST_AUTO_TEST_CASE(external_array_args) compileAndRun(sourceCode); bytes params = encodeArgs( 1, 2, 3, 4, 5, 6, 7, 8, // a - 3, // b.length + 32 * (8 + 1 + 5 + 1 + 1 + 1), // offset to b 21, 22, 23, 24, 25, // c 0, 1, 2, // (a,b,c)_index + 3, // b.length 11, 12, 13 // b ); BOOST_CHECK(callContractFunction("test(uint256[8],uint256[],uint256[5],uint256,uint256,uint256)", params) == encodeArgs(1, 12, 23)); @@ -3422,8 +3424,8 @@ BOOST_AUTO_TEST_CASE(bytes_index_access) 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; - BOOST_CHECK(callContractFunction("direct(bytes,uint256)", u256(array.length()), 32, array) == encodeArgs(32)); - BOOST_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", u256(array.length()), 32, array) == encodeArgs(32)); + BOOST_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array) == encodeArgs(33)); + BOOST_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array) == encodeArgs(33)); BOOST_CHECK(callContractFunction("storageWrite()") == encodeArgs(0x193)); } @@ -3474,6 +3476,7 @@ BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs( 21, 22, 23, 24, 25, 26, 27, 28, 29, // a + u256(32 * (9 + 1)), 4, // size of b 1, 2, 3, // b[0] 11, 12, 13, // b[1] @@ -3502,7 +3505,7 @@ BOOST_AUTO_TEST_CASE(array_copy_nested_array) )"; compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("test(uint256[2][])", encodeArgs( - 3, + 32, 3, 7, 8, 9, 10, 11, 12 From 260125a5d31f0048cbceb800ef5ad29f83c266db Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 5 May 2015 12:33:41 +0200 Subject: [PATCH 61/87] added test --- .../SolidityNameAndTypeResolution.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index c317dad97..9616777ab 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1761,6 +1761,25 @@ BOOST_AUTO_TEST_CASE(uninitialized_var) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(deny_overwriting_of_attributes_when_deriving) +{ + // bug #1798 + char const* sourceCode = R"( + contract owned { + address owner; + } + + contract reg { + function owner(bytes32 x) returns (address) {} + } + + contract x is owned, reg { + } + )"; + ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode), "Parsing and Name Resolving Failed"); + //BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From 328d40450f5aa20f631b2e8a5a394be044e132fe Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 7 May 2015 10:12:27 +0200 Subject: [PATCH 62/87] changed the way of resolving declarations. now the cleanup of function duplications in libsolidity/NameAndTypeResolver.cpp(WIP) --- libsolidity/AST.h | 8 ++-- libsolidity/DeclarationContainer.cpp | 10 ++-- libsolidity/DeclarationContainer.h | 8 ++-- libsolidity/NameAndTypeResolver.cpp | 69 ++++++++++++++-------------- libsolidity/NameAndTypeResolver.h | 13 +++--- libsolidity/Types.h | 1 + 6 files changed, 55 insertions(+), 54 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index fde0b71b0..be118be3d 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -1217,10 +1217,10 @@ public: } Declaration const& getReferencedDeclaration() const; - /// Stores a set of possible declarations referenced by this identifier. Has to be resolved + /// Stores a possible declarations referenced by this identifier. Has to be resolved /// providing argument types using overloadResolution before the referenced declaration /// is accessed. - void setOverloadedDeclarations(std::set const& _declarations) + void setOverloadedDeclarations(std::vector const& _declarations) { m_overloadedDeclarations = _declarations; } @@ -1237,8 +1237,8 @@ private: /// Stores a reference to the current contract. This is needed because types of base contracts /// change depending on the context. ContractDefinition const* m_currentContract = nullptr; - /// A set of overloaded declarations, right now only FunctionDefinition has overloaded declarations. - std::set m_overloadedDeclarations; + /// A vector of overloaded declarations, right now only FunctionDefinition has overloaded declarations. + std::vector m_overloadedDeclarations; }; /** diff --git a/libsolidity/DeclarationContainer.cpp b/libsolidity/DeclarationContainer.cpp index c836663c7..ec8a59bb6 100644 --- a/libsolidity/DeclarationContainer.cpp +++ b/libsolidity/DeclarationContainer.cpp @@ -37,6 +37,7 @@ Declaration const* DeclarationContainer::conflictingDeclaration(Declaration cons declarations += m_declarations.at(name); if (m_invisibleDeclarations.count(name)) declarations += m_invisibleDeclarations.at(name); + if (dynamic_cast(&_declaration)) { // check that all other declarations with the same name are functions @@ -66,14 +67,13 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, return false; if (_invisible) - m_invisibleDeclarations[name].insert(&_declaration); + m_invisibleDeclarations[name].push_back(&_declaration); else - m_declarations[name].insert(&_declaration); - + m_declarations[name].push_back(&_declaration); return true; } -set DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const +std::vector DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const { solAssert(!_name.empty(), "Attempt to resolve empty name."); auto result = m_declarations.find(_name); @@ -81,5 +81,5 @@ set DeclarationContainer::resolveName(ASTString const& _name return result->second; if (_recursive && m_enclosingContainer) return m_enclosingContainer->resolveName(_name, true); - return set({}); + return vector({}); } diff --git a/libsolidity/DeclarationContainer.h b/libsolidity/DeclarationContainer.h index 94545eefb..0f0b57179 100644 --- a/libsolidity/DeclarationContainer.h +++ b/libsolidity/DeclarationContainer.h @@ -48,17 +48,17 @@ public: /// @param _update if true, replaces a potential declaration that is already present /// @returns false if the name was already declared. bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false); - std::set resolveName(ASTString const& _name, bool _recursive = false) const; + std::vector resolveName(ASTString const& _name, bool _recursive = false) const; Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } - std::map> const& getDeclarations() const { return m_declarations; } + std::map> const& getDeclarations() const { return m_declarations; } /// @returns whether declaration is valid, and if not also returns previous declaration. Declaration const* conflictingDeclaration(Declaration const& _declaration) const; private: Declaration const* m_enclosingDeclaration; DeclarationContainer const* m_enclosingContainer; - std::map> m_declarations; - std::map> m_invisibleDeclarations; + std::map> m_declarations; + std::map> m_invisibleDeclarations; }; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 9aebbf054..4d33048dc 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -53,9 +53,13 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) m_currentScope = &m_scopes[&_contract]; linearizeBaseContracts(_contract); - // we first import non-functions only as we do not yet know the argument types - for (ContractDefinition const* base: _contract.getLinearizedBaseContracts()) - importInheritedScope(*base, false); // import non-functions + std::vector realBases( + ++_contract.getLinearizedBaseContracts().begin(), + _contract.getLinearizedBaseContracts().end() + ); + + for (ContractDefinition const* base: realBases) + importInheritedScope(*base); for (ASTPointer const& structDef: _contract.getDefinedStructs()) ReferencesResolver resolver(*structDef, *this, &_contract, nullptr); @@ -80,8 +84,6 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) } m_currentScope = &m_scopes[&_contract]; - for (ContractDefinition const* base: _contract.getLinearizedBaseContracts()) - importInheritedScope(*base, true); // import functions // now resolve references inside the code for (ASTPointer const& modifier: _contract.getFunctionModifiers()) @@ -115,20 +117,41 @@ void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope."); } -set NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const +vector NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const { auto iterator = m_scopes.find(_scope); if (iterator == end(m_scopes)) - return set({}); + return vector({}); return iterator->second.resolveName(_name, false); } -set NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) +vector NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) { return m_currentScope->resolveName(_name, _recursive); } -void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base, bool _importFunctions) +vector NameAndTypeResolver::cleanupedDeclarations(Identifier const& _identifier) +{ + vector result; + for (auto declaration : m_currentScope->resolveName(_identifier.getName())) + { + solAssert(declaration, ""); + // the declaration is functionDefinition while declarations > 1 + FunctionDefinition const& functionDefinition = dynamic_cast(*declaration); + FunctionType functionType(functionDefinition); + for(auto parameter: functionType.getParameterTypes() + functionType.getReturnParameterTypes()) + if (!parameter) + BOOST_THROW_EXCEPTION( + DeclarationError() << + errinfo_sourceLocation(_identifier.getLocation()) << + errinfo_comment("Function type can not be used in this context") + ); + //////////delete repitations. check by hasequalparameter types of function type + } + return result; +} + +void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) { auto iterator = m_scopes.find(&_base); solAssert(iterator != end(m_scopes), ""); @@ -136,30 +159,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base, for (auto const& declaration: nameAndDeclaration.second) // Import if it was declared in the base, is not the constructor and is visible in derived classes if (declaration->getScope() == &_base && declaration->isVisibleInDerivedContracts()) - { - auto function = dynamic_cast(declaration); - if ((function == nullptr) == _importFunctions) - continue; - if (!!function) - { - FunctionType functionType(*function); - // only import if a function with the same arguments does not exist yet - bool functionWithEqualArgumentsFound = false; - for (auto knownDeclaration: m_currentScope->resolveName(nameAndDeclaration.first)) - { - auto knownFunction = dynamic_cast(knownDeclaration); - if (!knownFunction) - continue; // this is not legal, but will be caught later - if (!FunctionType(*knownFunction).hasEqualArgumentTypes(functionType)) - continue; - functionWithEqualArgumentsFound = true; - break; - } - if (functionWithEqualArgumentsFound) - continue; - } m_currentScope->registerDeclaration(*declaration); - } } void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) const @@ -465,10 +465,9 @@ bool ReferencesResolver::visit(Identifier& _identifier) errinfo_comment("Undeclared identifier.") ); else if (declarations.size() == 1) - _identifier.setReferencedDeclaration(**declarations.begin(), m_currentContract); + _identifier.setReferencedDeclaration(*declarations.front(), m_currentContract); else - // Duplicate declaration will be checked in checkTypeRequirements() - _identifier.setOverloadedDeclarations(declarations); + _identifier.setOverloadedDeclarations(m_resolver.cleanupedDeclarations(_identifier)); return false; } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 6528bbef2..21857352c 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -56,19 +56,20 @@ public: /// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted, /// the global scope is used (i.e. the one containing only the contract). /// @returns a pointer to the declaration on success or nullptr on failure. - std::set resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; + std::vector resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; /// Resolves a name in the "current" scope. Should only be called during the initial /// resolving phase. - std::set getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); + std::vector getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); + + std::vector cleanupedDeclarations(Identifier const& _identifier); private: void reset(); - /// Either imports all non-function members or all function members declared directly in the - /// given contract (i.e. does not import inherited members) into the current scope if they are - ///not present already. - void importInheritedScope(ContractDefinition const& _base, bool _importFunctions); + /// Imports all members declared directly in the given contract (i.e. does not import inherited members) + /// into the current scope if they are not present already. + void importInheritedScope(ContractDefinition const& _base); /// Computes "C3-Linearization" of base contracts and stores it inside the contract. void linearizeBaseContracts(ContractDefinition& _contract) const; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 65a6867d6..5b95e5567 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -617,6 +617,7 @@ public: /// @returns true if this function can take the given argument types (possibly /// after implicit conversion). bool canTakeArguments(TypePointers const& _arguments) const; + /// @returns true if the types of parameters are equal(does't check return parameter types) bool hasEqualArgumentTypes(FunctionType const& _other) const; Location const& getLocation() const { return m_location; } From 91b7f87c56096ddeaa4ef1eebd0349e01d29af36 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 7 May 2015 16:52:06 +0200 Subject: [PATCH 63/87] implemented cleanup of duplication in resolver --- libsolidity/AST.cpp | 3 +++ libsolidity/NameAndTypeResolver.cpp | 25 +++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 2f98ce4f6..2ef3b03e8 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -954,6 +954,9 @@ Declaration const& Identifier::getReferencedDeclaration() const void Identifier::overloadResolution(TypePointers const& _argumentTypes) { solAssert(!m_referencedDeclaration, "Referenced declaration should be null before overload resolution."); + //to delete + if (m_overloadedDeclarations.empty()) + //---------------------------> solAssert(!m_overloadedDeclarations.empty(), "No candidates for overload resolution found."); vector possibles; diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 4d33048dc..ac841fccc 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -132,12 +132,14 @@ vector NameAndTypeResolver::getNameFromCurrentScope(ASTStrin vector NameAndTypeResolver::cleanupedDeclarations(Identifier const& _identifier) { - vector result; - for (auto declaration : m_currentScope->resolveName(_identifier.getName())) + vector uniqueFunctions; + + auto declarations = m_currentScope->resolveName(_identifier.getName()); + for (auto it = declarations.begin(); it != declarations.end(); ++it) { - solAssert(declaration, ""); + solAssert(*it, ""); // the declaration is functionDefinition while declarations > 1 - FunctionDefinition const& functionDefinition = dynamic_cast(*declaration); + FunctionDefinition const& functionDefinition = dynamic_cast(**it); FunctionType functionType(functionDefinition); for(auto parameter: functionType.getParameterTypes() + functionType.getReturnParameterTypes()) if (!parameter) @@ -146,9 +148,20 @@ vector NameAndTypeResolver::cleanupedDeclarations(Identifier errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Function type can not be used in this context") ); - //////////delete repitations. check by hasequalparameter types of function type + if (uniqueFunctions.end() == find_if( + uniqueFunctions.begin(), + uniqueFunctions.end(), + [&](Declaration const* d) + { + FunctionDefinition const& newFunctionDefinition = dynamic_cast(*d); + FunctionType newFunctionType(newFunctionDefinition); + + return functionType.hasEqualArgumentTypes(newFunctionType); + } + )) + uniqueFunctions.push_back(*it); } - return result; + return uniqueFunctions; } void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) From 71c2c7da45738a97d2c24590dfeac3fc72033015 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 7 May 2015 18:12:58 +0200 Subject: [PATCH 64/87] fixed the test --- libsolidity/NameAndTypeResolver.cpp | 10 ++++--- libsolidity/NameAndTypeResolver.h | 2 +- test/libsolidity/SolidityEndToEndTest.cpp | 29 +++++++++++++++++++ .../SolidityNameAndTypeResolution.cpp | 19 ------------ 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index ac841fccc..21b332924 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -130,12 +130,14 @@ vector NameAndTypeResolver::getNameFromCurrentScope(ASTStrin return m_currentScope->resolveName(_name, _recursive); } -vector NameAndTypeResolver::cleanupedDeclarations(Identifier const& _identifier) +vector NameAndTypeResolver::cleanupedDeclarations( + Identifier const& _identifier, + vector const& _declarations +) { vector uniqueFunctions; - auto declarations = m_currentScope->resolveName(_identifier.getName()); - for (auto it = declarations.begin(); it != declarations.end(); ++it) + for (auto it = _declarations.begin(); it != _declarations.end(); ++it) { solAssert(*it, ""); // the declaration is functionDefinition while declarations > 1 @@ -480,7 +482,7 @@ bool ReferencesResolver::visit(Identifier& _identifier) else if (declarations.size() == 1) _identifier.setReferencedDeclaration(*declarations.front(), m_currentContract); else - _identifier.setOverloadedDeclarations(m_resolver.cleanupedDeclarations(_identifier)); + _identifier.setOverloadedDeclarations(m_resolver.cleanupedDeclarations(_identifier, declarations)); return false; } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 21857352c..7855217a2 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -62,7 +62,7 @@ public: /// resolving phase. std::vector getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); - std::vector cleanupedDeclarations(Identifier const& _identifier); + std::vector cleanupedDeclarations(Identifier const& _identifier, std::vector const& _declarations); private: void reset(); diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f168ad454..2fd1e2ec2 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -3910,6 +3910,35 @@ BOOST_AUTO_TEST_CASE(external_types_in_calls) BOOST_CHECK(callContractFunction("nonexisting") == encodeArgs(u256(9))); } +BOOST_AUTO_TEST_CASE(proper_order_of_overwriting_of_attributes) +{ + // bug #1798 + char const* sourceCode = R"( + contract init { + function isOk() returns (bool) { return false; } + bool public ok = false; + } + contract fix { + function isOk() returns (bool) { return true; } + bool public ok = true; + } + + contract init_fix is init, fix { + function checkOk() returns (bool) { return ok; } + } + contract fix_init is fix, init { + function checkOk() returns (bool) { return ok; } + } + )"; + compileAndRun(sourceCode, 0, "init_fix"); + BOOST_CHECK(callContractFunction("isOk()") == encodeArgs(true)); + BOOST_CHECK(callContractFunction("ok()") == encodeArgs(true)); + + compileAndRun(sourceCode, 0, "fix_init"); + BOOST_CHECK(callContractFunction("isOk()") == encodeArgs(false)); + BOOST_CHECK(callContractFunction("ok()") == encodeArgs(false)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 9616777ab..c317dad97 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1761,25 +1761,6 @@ BOOST_AUTO_TEST_CASE(uninitialized_var) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } -BOOST_AUTO_TEST_CASE(deny_overwriting_of_attributes_when_deriving) -{ - // bug #1798 - char const* sourceCode = R"( - contract owned { - address owner; - } - - contract reg { - function owner(bytes32 x) returns (address) {} - } - - contract x is owned, reg { - } - )"; - ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode), "Parsing and Name Resolving Failed"); - //BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); -} - BOOST_AUTO_TEST_SUITE_END() } From 4081752e6361d2561549e668627b0bb010f3a854 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 8 May 2015 16:07:25 +0200 Subject: [PATCH 65/87] style changes --- libsolidity/AST.cpp | 3 --- libsolidity/AST.h | 2 +- libsolidity/DeclarationContainer.cpp | 2 +- libsolidity/NameAndTypeResolver.cpp | 15 +++++++-------- libsolidity/NameAndTypeResolver.h | 8 ++++++-- libsolidity/Types.h | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 2ef3b03e8..2f98ce4f6 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -954,9 +954,6 @@ Declaration const& Identifier::getReferencedDeclaration() const void Identifier::overloadResolution(TypePointers const& _argumentTypes) { solAssert(!m_referencedDeclaration, "Referenced declaration should be null before overload resolution."); - //to delete - if (m_overloadedDeclarations.empty()) - //---------------------------> solAssert(!m_overloadedDeclarations.empty(), "No candidates for overload resolution found."); vector possibles; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index be118be3d..be5c9a6cd 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -1217,7 +1217,7 @@ public: } Declaration const& getReferencedDeclaration() const; - /// Stores a possible declarations referenced by this identifier. Has to be resolved + /// Stores a set of possible declarations referenced by this identifier. Has to be resolved /// providing argument types using overloadResolution before the referenced declaration /// is accessed. void setOverloadedDeclarations(std::vector const& _declarations) diff --git a/libsolidity/DeclarationContainer.cpp b/libsolidity/DeclarationContainer.cpp index ec8a59bb6..3e23d93b8 100644 --- a/libsolidity/DeclarationContainer.cpp +++ b/libsolidity/DeclarationContainer.cpp @@ -73,7 +73,7 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, return true; } -std::vector DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const +std::vector DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const { solAssert(!_name.empty(), "Attempt to resolve empty name."); auto result = m_declarations.find(_name); diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 21b332924..5ef14f60b 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -53,12 +53,12 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) m_currentScope = &m_scopes[&_contract]; linearizeBaseContracts(_contract); - std::vector realBases( + std::vector properBases( ++_contract.getLinearizedBaseContracts().begin(), _contract.getLinearizedBaseContracts().end() ); - for (ContractDefinition const* base: realBases) + for (ContractDefinition const* base: properBases) importInheritedScope(*base); for (ASTPointer const& structDef: _contract.getDefinedStructs()) @@ -130,11 +130,12 @@ vector NameAndTypeResolver::getNameFromCurrentScope(ASTStrin return m_currentScope->resolveName(_name, _recursive); } -vector NameAndTypeResolver::cleanupedDeclarations( +vector NameAndTypeResolver::cleanedDeclarations( Identifier const& _identifier, vector const& _declarations ) { + solAssert(_declarations.size() > 1, ""); vector uniqueFunctions; for (auto it = _declarations.begin(); it != _declarations.end(); ++it) @@ -143,7 +144,7 @@ vector NameAndTypeResolver::cleanupedDeclarations( // the declaration is functionDefinition while declarations > 1 FunctionDefinition const& functionDefinition = dynamic_cast(**it); FunctionType functionType(functionDefinition); - for(auto parameter: functionType.getParameterTypes() + functionType.getReturnParameterTypes()) + for (auto parameter: functionType.getParameterTypes() + functionType.getReturnParameterTypes()) if (!parameter) BOOST_THROW_EXCEPTION( DeclarationError() << @@ -155,9 +156,7 @@ vector NameAndTypeResolver::cleanupedDeclarations( uniqueFunctions.end(), [&](Declaration const* d) { - FunctionDefinition const& newFunctionDefinition = dynamic_cast(*d); - FunctionType newFunctionType(newFunctionDefinition); - + FunctionType newFunctionType(dynamic_cast(*d)); return functionType.hasEqualArgumentTypes(newFunctionType); } )) @@ -482,7 +481,7 @@ bool ReferencesResolver::visit(Identifier& _identifier) else if (declarations.size() == 1) _identifier.setReferencedDeclaration(*declarations.front(), m_currentContract); else - _identifier.setOverloadedDeclarations(m_resolver.cleanupedDeclarations(_identifier, declarations)); + _identifier.setOverloadedDeclarations(m_resolver.cleanedDeclarations(_identifier, declarations)); return false; } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 7855217a2..d7a0a3b2f 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -56,13 +56,17 @@ public: /// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted, /// the global scope is used (i.e. the one containing only the contract). /// @returns a pointer to the declaration on success or nullptr on failure. - std::vector resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; + std::vector resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const; /// Resolves a name in the "current" scope. Should only be called during the initial /// resolving phase. std::vector getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); - std::vector cleanupedDeclarations(Identifier const& _identifier, std::vector const& _declarations); + /// returns the vector of declarations without repetitions + static std::vector cleanedDeclarations( + Identifier const& _identifier, + std::vector const& _declarations + ); private: void reset(); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 5b95e5567..da2fcdb89 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -617,7 +617,7 @@ public: /// @returns true if this function can take the given argument types (possibly /// after implicit conversion). bool canTakeArguments(TypePointers const& _arguments) const; - /// @returns true if the types of parameters are equal(does't check return parameter types) + /// @returns true if the types of parameters are equal (does't check return parameter types) bool hasEqualArgumentTypes(FunctionType const& _other) const; Location const& getLocation() const { return m_location; } From ce64ea610c11e8b8e53267bea909198588ce9499 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 8 May 2015 17:50:44 +0200 Subject: [PATCH 66/87] added one more test --- test/libsolidity/SolidityEndToEndTest.cpp | 55 +++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 2fd1e2ec2..f32439a27 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -3939,6 +3939,61 @@ BOOST_AUTO_TEST_CASE(proper_order_of_overwriting_of_attributes) BOOST_CHECK(callContractFunction("ok()") == encodeArgs(false)); } +BOOST_AUTO_TEST_CASE(proper_overwriting_accessor_by_function) +{ + // bug #1798 + char const* sourceCode = R"( + contract attribute { + bool ok = false; + } + contract func { + function ok() returns (bool) { return true; } + } + + contract attr_func is attribute, func { + function checkOk() returns (bool) { return ok(); } + } + contract func_attr is func, attribute { + function checkOk() returns (bool) { return ok; } + } + )"; + compileAndRun(sourceCode, 0, "attr_func"); + BOOST_CHECK(callContractFunction("ok()") == encodeArgs(true)); + compileAndRun(sourceCode, 0, "func_attr"); + BOOST_CHECK(callContractFunction("checkOk()") == encodeArgs(false)); +} + + +BOOST_AUTO_TEST_CASE(overwriting_inheritance) +{ + // bug #1798 + char const* sourceCode = R"( + contract A { + function ok() returns (uint) { return 1; } + } + contract B { + function ok() returns (uint) { return 2; } + } + contract C { + uint ok = 6; + } + contract AB is A, B { + function ok() returns (uint) { return 4; } + } + contract reversedE is C, AB { + function checkOk() returns (uint) { return ok(); } + } + contract E is AB, C { + function checkOk() returns (uint) { return ok; } + } + )"; + compileAndRun(sourceCode, 0, "reversedE"); + BOOST_CHECK(callContractFunction("checkOk()") == encodeArgs(4)); + compileAndRun(sourceCode, 0, "E"); + BOOST_CHECK(callContractFunction("checkOk()") == encodeArgs(6)); +} + + BOOST_AUTO_TEST_SUITE_END() } From b2857b26eace95c5febf001f868f5e1b6fb49c0f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 8 May 2015 18:57:48 +0300 Subject: [PATCH 67/87] Version bump, KeyManager. --- exp/main.cpp | 161 ++++++++++++++++++++++++++++++++++++------ libdevcore/Common.cpp | 2 +- 2 files changed, 142 insertions(+), 21 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 5a57c091e..1788a64e4 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -67,40 +67,36 @@ namespace fs = boost::filesystem; inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); } inline std::string toUUID(h128 const& _uuid) { std::string ret = toHex(_uuid.ref()); for (unsigned i: {20, 16, 12, 8}) ret.insert(ret.begin() + i, '-'); return ret; } -class KeyManager: public Worker +class KeyStore { public: - KeyManager() { readKeys(); } - ~KeyManager() {} + KeyStore() { readKeys(); } + ~KeyStore() {} - Secret secret(h128 const& _uuid, function const& _pass) + bytes key(h128 const& _uuid, function const& _pass) { auto rit = m_cached.find(_uuid); if (rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); if (it == m_keys.end()) - return Secret(); - Secret ret(decrypt(it->second, _pass())); - if (ret) - m_cached[_uuid] = ret; - return ret; + return bytes(); + bytes key = decrypt(it->second, _pass()); + if (!key.empty()) + m_cached[_uuid] = key; + return key; } - h128 import(Secret const& _s, std::string const& _pass) + h128 import(bytes const& _s, std::string const& _pass) { - h128 r(sha3(_s)); + h128 r = h128::random(); m_cached[r] = _s; - m_keys[r] = encrypt(_s.asBytes(), _pass); + m_keys[r] = encrypt(_s, _pass); writeKeys(); return r; } - h128 create(std::string const& _pass) - { - return import(Secret::random(), _pass); - } - + // Clear any cached keys. void clearCache() const { m_cached.clear(); } private: @@ -137,8 +133,8 @@ private: else cwarn << "Cannot read key version" << version; } - else - cwarn << "Invalid JSON in key file" << it->path().string(); +// else +// cwarn << "Invalid JSON in key file" << it->path().string(); } } @@ -232,10 +228,135 @@ private: } } - mutable std::map m_cached; + mutable std::map m_cached; std::map m_keys; }; +class UnknownPassword: public Exception {}; + +struct KeyInfo +{ + h256 passHash; + std::string name; +}; + +static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); }; + +// This one is specifically for Ethereum, but we can make it generic in due course. +// TODO: hidden-partition style key-store. +class KeyManager +{ +public: + KeyManager() { m_cachedPasswords[sha3(m_password)] = m_password; } + ~KeyManager() {} + + void load(std::string const& _pass, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") + { + try { + bytes salt = contents(_keysFile + ".salt"); + bytes encKeys = contents(_keysFile); + m_key = h128(pbkdf2(_pass, salt, 262144, 16)); + bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys); + RLP s(bs); + unsigned version = (unsigned)s[0]; + if (version == 1) + { + for (auto const& i: s[1]) + m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo{(h256)i[2], (std::string)i[3]}; + for (auto const& i: s[2]) + m_passwordInfo[(h256)i[0]] = (std::string)i[1]; + m_password = (string)s[3]; + } + } + catch (...) {} + m_cachedPasswords[sha3(m_password)] = m_password; + } + + // Only use if previously loaded ok. + // @returns false if wasn't previously loaded ok. + bool save(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") { if (!m_key) return false; save(m_key, _keysFile); return true; } + + void save(std::string const& _pass, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") + { + bytes salt = h256::random().asBytes(); + writeFile(_keysFile + ".salt", salt); + auto key = h128(pbkdf2(_pass, salt, 262144, 16)); + save(key, _keysFile); + } + + void save(h128 const& _key, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") + { + RLPStream s(4); + s << 1; + s.appendList(m_addrLookup.size()); + for (auto const& i: m_addrLookup) + s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].name; + s.appendList(m_passwordInfo.size()); + for (auto const& i: m_passwordInfo) + s.appendList(2) << i.first << i.second; + s.append(m_password); + + writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out())); + m_key = _key; + } + + Secret secret(Address const& _address, function const& _pass = DontKnowThrow) + { + auto it = m_addrLookup.find(_address); + if (it == m_addrLookup.end()) + return Secret(); + return secret(it->second, _pass); + } + + Secret secret(h128 const& _uuid, function const& _pass = DontKnowThrow) + { + return Secret(m_store.key(_uuid, [&](){ + auto it = m_cachedPasswords.find(m_keyInfo[_uuid].passHash); + if (it == m_cachedPasswords.end()) + { + std::string p = _pass(); + m_cachedPasswords[sha3(p)] = p; + return p; + } + else + return it->second; + })); + } + + h128 import(Secret const& _s, std::string const& _pass, string const& _info = std::string(), string const& _passInfo = std::string()) + { + Address addr = KeyPair(_s).address(); + auto passHash = sha3(_pass); + m_cachedPasswords[passHash] = _pass; + m_passwordInfo[passHash] = _passInfo; + auto uuid = m_store.import(_s.asBytes(), _pass); + m_keyInfo[uuid] = KeyInfo{passHash, _info}; + m_addrLookup[addr] = uuid; + return uuid; + } + + h128 import(Secret const& _s, std::string const& _info = std::string()) + { + // cache password, remember the key, remember the address + return import(_s, m_password, _info, std::string()); + } + +private: + // Ethereum keys. + std::map m_addrLookup; + std::map m_keyInfo; + std::map m_passwordInfo; + + // Passwords that we're storing. + std::map m_cachedPasswords; + + // The default password for keys in the keystore - protected by the master password. + std::string m_password = asString(h256::random().asBytes()); + + KeyStore m_store; + h128 m_key; +}; + int main() { KeyManager keyman; diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 8afd6082e..d0d153fbf 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -28,7 +28,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.15o"; +char const* Version = "0.9.16"; void HasInvariants::checkInvariants() const { From 365372799e5f4d158dfb86cf6d0d2f6d6ecc5708 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 8 May 2015 18:07:56 +0200 Subject: [PATCH 68/87] Use range-based erase. --- libevmasm/KnownState.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index 7ff0143e1..41ac4802b 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -151,8 +151,10 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool ); } } - for (int p = m_stackHeight; p > m_stackHeight + _item.deposit(); --p) - m_stackElements.erase(p); + m_stackElements.erase( + m_stackElements.upper_bound(m_stackHeight + _item.deposit()), + m_stackElements.end() + ); m_stackHeight += _item.deposit(); } return op; From b75a90bc722d51b2790a9b2dad18b814f327533c Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 8 May 2015 21:52:20 +0200 Subject: [PATCH 69/87] used operator+= for bytes --- mix/ContractCallDataEncoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 9ea1c3510..07ab8dd73 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -74,7 +74,7 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& { bytes empty(32); size_t sizePos = m_dynamicData.size(); - m_dynamicData.insert(m_dynamicData.end(), empty.begin(), empty.end()); //reserve space for count + m_dynamicData += empty; //reserve space for count if (_type.type == SolidityType::Type::Bytes) count = encodeSingleItem(_data.toString(), _type, m_dynamicData); else @@ -86,7 +86,7 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& vector_ref sizeRef(m_dynamicData.data() + sizePos, 32); toBigEndian(count, sizeRef); m_offsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); - m_encodedData.insert(m_encodedData.end(), empty.begin(), empty.end()); //reserve space for offset + m_encodedData += empty; //reserve space for offset } else { From f52f8682c4604376c1fa352743a1142e89780a18 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 8 May 2015 22:40:46 +0200 Subject: [PATCH 70/87] reverted changed in NodeTable::nearestNodeEntries --- libp2p/NodeTable.cpp | 107 ++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index f04068852..90a7ac459 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -1,16 +1,16 @@ /* 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 . */ @@ -54,17 +54,17 @@ NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint m_state[i].distance = i; m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); } - + m_socketPointer->connect(); doRefreshBuckets(boost::system::error_code()); } - + NodeTable::~NodeTable() { // Cancel scheduled tasks to ensure. m_evictionCheckTimer.cancel(); m_bucketRefreshTimer.cancel(); - + // Disconnect socket so that deallocation is safe. m_socketPointer->disconnect(); } @@ -85,10 +85,10 @@ shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relati noteActiveNode(_node.id, _node.endpoint); return ret; } - + if (!_node.endpoint) return move(shared_ptr()); - + // ping address to recover nodeid if nodeid is empty if (!_node.id) { @@ -100,13 +100,13 @@ shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relati ping(_node.endpoint); return move(shared_ptr()); } - + { Guard ln(x_nodes); if (m_nodes.count(_node.id)) return m_nodes[_node.id]; } - + shared_ptr ret(new NodeEntry(m_node, _node.id, _node.endpoint)); m_nodes[_node.id] = ret; clog(NodeTableConnect) << "addNode pending for" << _node.endpoint; @@ -167,7 +167,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrisOpen() || _round == s_maxSteps) return; - + if (_round == s_maxSteps) { clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; @@ -176,7 +176,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr>()); - + auto nearest = nearestNodeEntries(_node); list> tried; for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) @@ -189,19 +189,19 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrid, chrono::steady_clock::now())); m_socketPointer->send(p); } - + if (tried.empty()) { clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; return; } - + while (!tried.empty()) { _tried->insert(tried.front()); tried.pop_front(); } - + auto self(shared_from_this()); m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(c_reqTimeout.count() * 2)); m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec) @@ -218,10 +218,10 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) static unsigned lastBin = s_bins - 1; unsigned head = distance(m_node.id, _target); unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins; - - unordered_multimap> found; + + map>> found; unsigned count = 0; - + // if d is 0, then we roll look forward, if last, we reverse, else, spread from d if (head > 1 && tail != lastBin) while (head != tail && head < s_bins && count < s_bucketSize) @@ -231,17 +231,17 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) if (auto p = n.lock()) { if (count < s_bucketSize) - found.insert(make_pair(distance(_target, p->id), p)); + found[distance(_target, p->id)].push_back(p); else break; } - + if (count < s_bucketSize && tail) for (auto n: m_state[tail].nodes) if (auto p = n.lock()) { if (count < s_bucketSize) - found.insert(make_pair(distance(_target, p->id), p)); + found[distance(_target, p->id)].push_back(p); else break; } @@ -258,7 +258,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) if (auto p = n.lock()) { if (count < s_bucketSize) - found.insert(make_pair(distance(_target, p->id), p)); + found[distance(_target, p->id)].push_back(p); else break; } @@ -272,17 +272,18 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) if (auto p = n.lock()) { if (count < s_bucketSize) - found.insert(make_pair(distance(_target, p->id), p)); + found[distance(_target, p->id)].push_back(p); else break; } tail--; } - + vector> ret; - for (auto n: found) - if (ret.size() < s_bucketSize && !!n.second->endpoint && n.second->endpoint.isAllowed()) - ret.push_back(n.second); + for (auto& nodes: found) + for (auto n: nodes.second) + if (ret.size() < s_bucketSize && !!n->endpoint && n->endpoint.isAllowed()) + ret.push_back(n); return move(ret); } @@ -303,7 +304,7 @@ void NodeTable::evict(shared_ptr _leastSeen, shared_ptr _n { if (!m_socketPointer->isOpen()) return; - + { Guard l(x_evictions); m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); @@ -324,7 +325,7 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en clog(NodeTableConnect) << "Noting active node:" << _pubk << _endpoint.address().to_string() << ":" << _endpoint.port(); node->endpoint.address = _endpoint.address(); node->endpoint.udpPort = _endpoint.port(); - + shared_ptr contested; { Guard l(x_state); @@ -336,7 +337,7 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en removed = true; return removed; }); - + if (s.nodes.size() >= s_bucketSize) { // It's only contested iff nodeentry exists @@ -346,7 +347,7 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en s.nodes.pop_front(); s.nodes.push_back(node); s.touch(); - + if (!removed && m_nodeEventHandler) m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded); } @@ -355,12 +356,12 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en { s.nodes.push_back(node); s.touch(); - + if (!removed && m_nodeEventHandler) m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded); } } - + if (contested) evict(contested, node); } @@ -374,7 +375,7 @@ void NodeTable::dropNode(shared_ptr _n) NodeBucket& s = bucket_UNSAFE(_n.get()); s.nodes.remove_if([&_n](weak_ptr n) { return n.lock() == _n; }); } - + // notify host clog(NodeTableUpdate) << "p2p.nodes.drop " << _n->id; if (m_nodeEventHandler) @@ -394,7 +395,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableTriviaSummary) << "Invalid message size from " << _from.address().to_string() << ":" << _from.port(); return; } - + bytesConstRef hashedBytes(_packet.cropped(h256::size, _packet.size() - h256::size)); h256 hashSigned(sha3(hashedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) @@ -402,11 +403,11 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableTriviaSummary) << "Invalid message hash from " << _from.address().to_string() << ":" << _from.port(); return; } - + bytesConstRef signedBytes(hashedBytes.cropped(Signature::size, hashedBytes.size() - Signature::size)); // todo: verify sig via known-nodeid and MDC - + bytesConstRef sigBytes(_packet.cropped(h256::size, Signature::size)); Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(signedBytes))); if (!nodeid) @@ -414,7 +415,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableTriviaSummary) << "Invalid message signature from " << _from.address().to_string() << ":" << _from.port(); return; } - + unsigned packetType = signedBytes[0]; bytesConstRef rlpBytes(_packet.cropped(h256::size + Signature::size + 1)); RLP rlp(rlpBytes); @@ -424,7 +425,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case Pong::type: { Pong in = Pong::fromBytesConstRef(_from, rlpBytes); - + // whenever a pong is received, check if it's in m_evictions Guard le(x_evictions); bool evictionEntry = false; @@ -434,13 +435,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes evictionEntry = true; if (auto n = nodeEntry(it->second)) dropNode(n); - + if (auto n = nodeEntry(it->first.first)) n->pending = false; - + it = m_evictions.erase(it); } - + // if not, check if it's known/pending or a pubk discovery ping if (!evictionEntry) { @@ -458,16 +459,16 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes else return; // unsolicited pong; don't note node as active } - + // update our endpoint address and UDP port if ((!m_node.endpoint || !m_node.endpoint.isAllowed()) && isPublicAddress(in.destination.address)) m_node.endpoint.address = in.destination.address; m_node.endpoint.udpPort = in.destination.udpPort; - + clog(NodeTableConnect) << "PONG from " << nodeid << _from; break; } - + case Neighbours::type: { bool expected = false; @@ -480,13 +481,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes return true; return false; }); - + if (!expected) { clog(NetConnect) << "Dropping unsolicited neighbours packet from " << _from.address(); break; } - + Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); for (auto n: in.neighbours) addNode(Node(n.node, n.endpoint)); @@ -530,13 +531,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes else return; } - + if (RLPXDatagramFace::secondsSinceEpoch() > in.ts) { clog(NodeTableTriviaSummary) << "Received expired PingNode from " << _from.address().to_string() << ":" << _from.port(); return; } - + in.source.address = _from.address(); in.source.udpPort = _from.port(); addNode(Node(nodeid, in.source)); @@ -546,7 +547,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes m_socketPointer->send(p); break; } - + default: clog(NodeTableWarn) << "Invalid message, " << hex << packetType << ", received from " << _from.address().to_string() << ":" << dec << _from.port(); return; @@ -571,7 +572,7 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) { if (_ec) return; - + bool evictionsRemain = false; list> drop; { @@ -583,11 +584,11 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) drop.push_back(m_nodes[e.second]); evictionsRemain = m_evictions.size() - drop.size() > 0; } - + drop.unique(); for (auto n: drop) dropNode(n); - + if (evictionsRemain) doCheckEvictions(boost::system::error_code()); }); From 5028ce313135975b933417a6af9e92ed89b140e5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 8 May 2015 23:16:04 +0200 Subject: [PATCH 71/87] fixed a comment after sloppy merge --- libp2p/NodeTable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 0ae534b20..92bf17f79 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -254,7 +254,7 @@ private: mutable Mutex x_state; ///< LOCK x_state first if both x_nodes and x_state locks are required. std::array m_state; ///< State of p2p node network. - Mutex x_evictions; ///< LOCK x_nodes first if both x_nodes and x_evictions locks are required. + Mutex x_evictions; ///< LOCK x_evictions first if both x_nodes and x_evictions locks are required. std::deque m_evictions; ///< Eviction timeouts. Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required. From 990582cc7adc51c08255dfb8623b76bd5b498fee Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 8 May 2015 23:21:16 +0200 Subject: [PATCH 72/87] reverted NodeTable.cpp --- libp2p/NodeTable.cpp | 90 ++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 90a7ac459..c3215da71 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -1,16 +1,16 @@ /* 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 . */ @@ -54,17 +54,17 @@ NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint m_state[i].distance = i; m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); } - + m_socketPointer->connect(); doRefreshBuckets(boost::system::error_code()); } - + NodeTable::~NodeTable() { // Cancel scheduled tasks to ensure. m_evictionCheckTimer.cancel(); m_bucketRefreshTimer.cancel(); - + // Disconnect socket so that deallocation is safe. m_socketPointer->disconnect(); } @@ -85,10 +85,10 @@ shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relati noteActiveNode(_node.id, _node.endpoint); return ret; } - + if (!_node.endpoint) return move(shared_ptr()); - + // ping address to recover nodeid if nodeid is empty if (!_node.id) { @@ -100,13 +100,13 @@ shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relati ping(_node.endpoint); return move(shared_ptr()); } - + { Guard ln(x_nodes); if (m_nodes.count(_node.id)) return m_nodes[_node.id]; } - + shared_ptr ret(new NodeEntry(m_node, _node.id, _node.endpoint)); m_nodes[_node.id] = ret; clog(NodeTableConnect) << "addNode pending for" << _node.endpoint; @@ -167,7 +167,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrisOpen() || _round == s_maxSteps) return; - + if (_round == s_maxSteps) { clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; @@ -176,7 +176,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr>()); - + auto nearest = nearestNodeEntries(_node); list> tried; for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) @@ -189,19 +189,19 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrid, chrono::steady_clock::now())); m_socketPointer->send(p); } - + if (tried.empty()) { clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; return; } - + while (!tried.empty()) { _tried->insert(tried.front()); tried.pop_front(); } - + auto self(shared_from_this()); m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(c_reqTimeout.count() * 2)); m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec) @@ -218,10 +218,10 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) static unsigned lastBin = s_bins - 1; unsigned head = distance(m_node.id, _target); unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins; - + map>> found; unsigned count = 0; - + // if d is 0, then we roll look forward, if last, we reverse, else, spread from d if (head > 1 && tail != lastBin) while (head != tail && head < s_bins && count < s_bucketSize) @@ -235,7 +235,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) else break; } - + if (count < s_bucketSize && tail) for (auto n: m_state[tail].nodes) if (auto p = n.lock()) @@ -278,7 +278,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) } tail--; } - + vector> ret; for (auto& nodes: found) for (auto n: nodes.second) @@ -304,7 +304,7 @@ void NodeTable::evict(shared_ptr _leastSeen, shared_ptr _n { if (!m_socketPointer->isOpen()) return; - + { Guard l(x_evictions); m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); @@ -325,7 +325,7 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en clog(NodeTableConnect) << "Noting active node:" << _pubk << _endpoint.address().to_string() << ":" << _endpoint.port(); node->endpoint.address = _endpoint.address(); node->endpoint.udpPort = _endpoint.port(); - + shared_ptr contested; { Guard l(x_state); @@ -337,7 +337,7 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en removed = true; return removed; }); - + if (s.nodes.size() >= s_bucketSize) { // It's only contested iff nodeentry exists @@ -347,7 +347,7 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en s.nodes.pop_front(); s.nodes.push_back(node); s.touch(); - + if (!removed && m_nodeEventHandler) m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded); } @@ -356,12 +356,12 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en { s.nodes.push_back(node); s.touch(); - + if (!removed && m_nodeEventHandler) m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded); } } - + if (contested) evict(contested, node); } @@ -375,7 +375,7 @@ void NodeTable::dropNode(shared_ptr _n) NodeBucket& s = bucket_UNSAFE(_n.get()); s.nodes.remove_if([&_n](weak_ptr n) { return n.lock() == _n; }); } - + // notify host clog(NodeTableUpdate) << "p2p.nodes.drop " << _n->id; if (m_nodeEventHandler) @@ -395,7 +395,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableTriviaSummary) << "Invalid message size from " << _from.address().to_string() << ":" << _from.port(); return; } - + bytesConstRef hashedBytes(_packet.cropped(h256::size, _packet.size() - h256::size)); h256 hashSigned(sha3(hashedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) @@ -403,11 +403,11 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableTriviaSummary) << "Invalid message hash from " << _from.address().to_string() << ":" << _from.port(); return; } - + bytesConstRef signedBytes(hashedBytes.cropped(Signature::size, hashedBytes.size() - Signature::size)); // todo: verify sig via known-nodeid and MDC - + bytesConstRef sigBytes(_packet.cropped(h256::size, Signature::size)); Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(signedBytes))); if (!nodeid) @@ -415,7 +415,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableTriviaSummary) << "Invalid message signature from " << _from.address().to_string() << ":" << _from.port(); return; } - + unsigned packetType = signedBytes[0]; bytesConstRef rlpBytes(_packet.cropped(h256::size + Signature::size + 1)); RLP rlp(rlpBytes); @@ -425,7 +425,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case Pong::type: { Pong in = Pong::fromBytesConstRef(_from, rlpBytes); - + // whenever a pong is received, check if it's in m_evictions Guard le(x_evictions); bool evictionEntry = false; @@ -435,13 +435,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes evictionEntry = true; if (auto n = nodeEntry(it->second)) dropNode(n); - + if (auto n = nodeEntry(it->first.first)) n->pending = false; - + it = m_evictions.erase(it); } - + // if not, check if it's known/pending or a pubk discovery ping if (!evictionEntry) { @@ -459,16 +459,16 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes else return; // unsolicited pong; don't note node as active } - + // update our endpoint address and UDP port if ((!m_node.endpoint || !m_node.endpoint.isAllowed()) && isPublicAddress(in.destination.address)) m_node.endpoint.address = in.destination.address; m_node.endpoint.udpPort = in.destination.udpPort; - + clog(NodeTableConnect) << "PONG from " << nodeid << _from; break; } - + case Neighbours::type: { bool expected = false; @@ -481,13 +481,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes return true; return false; }); - + if (!expected) { clog(NetConnect) << "Dropping unsolicited neighbours packet from " << _from.address(); break; } - + Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); for (auto n: in.neighbours) addNode(Node(n.node, n.endpoint)); @@ -531,13 +531,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes else return; } - + if (RLPXDatagramFace::secondsSinceEpoch() > in.ts) { clog(NodeTableTriviaSummary) << "Received expired PingNode from " << _from.address().to_string() << ":" << _from.port(); return; } - + in.source.address = _from.address(); in.source.udpPort = _from.port(); addNode(Node(nodeid, in.source)); @@ -547,7 +547,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes m_socketPointer->send(p); break; } - + default: clog(NodeTableWarn) << "Invalid message, " << hex << packetType << ", received from " << _from.address().to_string() << ":" << dec << _from.port(); return; @@ -572,7 +572,7 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) { if (_ec) return; - + bool evictionsRemain = false; list> drop; { @@ -584,11 +584,11 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) drop.push_back(m_nodes[e.second]); evictionsRemain = m_evictions.size() - drop.size() > 0; } - + drop.unique(); for (auto n: drop) dropNode(n); - + if (evictionsRemain) doCheckEvictions(boost::system::error_code()); }); From 9ef9e7cf82e63f74ccd79cd0070c657f0bbbbeec Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 May 2015 13:15:52 +0300 Subject: [PATCH 73/87] Encrypted KeyManager can import, write itself &c. --- exp/main.cpp | 132 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 34 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 1788a64e4..9b6813ccf 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -242,19 +242,41 @@ struct KeyInfo static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); }; -// This one is specifically for Ethereum, but we can make it generic in due course. +// TODO: This one is specifically for Ethereum, but we can make it generic in due course. // TODO: hidden-partition style key-store. +/** + * @brief High-level manager of keys for Ethereum. + * Usage: + * + * Call exists() to check whether there is already a database. If so, get the master password from + * the user and call load() with it. If not, get a new master password from the user (get them to type + * it twice and keep some hint around!) and call create() with it. + */ class KeyManager { public: - KeyManager() { m_cachedPasswords[sha3(m_password)] = m_password; } + KeyManager() {} ~KeyManager() {} - void load(std::string const& _pass, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") + void setKeysFile(std::string const& _keysFile) { m_keysFile = _keysFile; } + std::string const& keysFile() const { return m_keysFile; } + + bool exists() + { + return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty(); + } + + void create(std::string const& _pass) + { + m_password = asString(h256::random().asBytes()); + save(_pass, m_keysFile); + } + + bool load(std::string const& _pass) { try { - bytes salt = contents(_keysFile + ".salt"); - bytes encKeys = contents(_keysFile); + bytes salt = contents(m_keysFile + ".salt"); + bytes encKeys = contents(m_keysFile); m_key = h128(pbkdf2(_pass, salt, 262144, 16)); bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys); RLP s(bs); @@ -267,37 +289,17 @@ public: m_passwordInfo[(h256)i[0]] = (std::string)i[1]; m_password = (string)s[3]; } + m_cachedPasswords[sha3(m_password)] = m_password; + return true; + } + catch (...) { + return false; } - catch (...) {} - m_cachedPasswords[sha3(m_password)] = m_password; - } - - // Only use if previously loaded ok. - // @returns false if wasn't previously loaded ok. - bool save(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") { if (!m_key) return false; save(m_key, _keysFile); return true; } - - void save(std::string const& _pass, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") - { - bytes salt = h256::random().asBytes(); - writeFile(_keysFile + ".salt", salt); - auto key = h128(pbkdf2(_pass, salt, 262144, 16)); - save(key, _keysFile); } - void save(h128 const& _key, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") + void resave(std::string const& _pass) { - RLPStream s(4); - s << 1; - s.appendList(m_addrLookup.size()); - for (auto const& i: m_addrLookup) - s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].name; - s.appendList(m_passwordInfo.size()); - for (auto const& i: m_passwordInfo) - s.appendList(2) << i.first << i.second; - s.append(m_password); - - writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out())); - m_key = _key; + save(_pass, m_keysFile); } Secret secret(Address const& _address, function const& _pass = DontKnowThrow) @@ -332,6 +334,7 @@ public: auto uuid = m_store.import(_s.asBytes(), _pass); m_keyInfo[uuid] = KeyInfo{passHash, _info}; m_addrLookup[addr] = uuid; + save(m_keysFile); return uuid; } @@ -341,7 +344,60 @@ public: return import(_s, m_password, _info, std::string()); } + void importExisting(h128 const& _uuid, std::string const& _pass, std::string const& _info = std::string(), std::string const& _passInfo = std::string()) + { + bytes key = m_store.key(_uuid, [&](){ return _pass; }); + if (key.empty()) + return; + Address a = KeyPair(Secret(key)).address(); + auto passHash = sha3(_pass); + if (!m_passwordInfo.count(passHash)) + m_passwordInfo[passHash] = _passInfo; + if (!m_cachedPasswords.count(passHash)) + m_cachedPasswords[passHash] = _pass; + m_addrLookup[a] = _uuid; + m_keyInfo[_uuid].passHash = passHash; + m_keyInfo[_uuid].name = _info; + save(m_keysFile); + } + + KeyStore& store() { return m_store; } + private: + // Only use if previously loaded ok. + // @returns false if wasn't previously loaded ok. + bool save(std::string const& _keysFile) + { + if (!m_key) + return false; + save(m_key, _keysFile); + return true; + } + + void save(std::string const& _pass, std::string const& _keysFile) + { + bytes salt = h256::random().asBytes(); + writeFile(_keysFile + ".salt", salt); + auto key = h128(pbkdf2(_pass, salt, 262144, 16)); + save(key, _keysFile); + } + + void save(h128 const& _key, std::string const& _keysFile) + { + RLPStream s(4); + s << 1; + s.appendList(m_addrLookup.size()); + for (auto const& i: m_addrLookup) + s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].name; + s.appendList(m_passwordInfo.size()); + for (auto const& i: m_passwordInfo) + s.appendList(2) << i.first << i.second; + s.append(m_password); + + writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out())); + m_key = _key; + } + // Ethereum keys. std::map m_addrLookup; std::map m_keyInfo; @@ -351,17 +407,25 @@ private: std::map m_cachedPasswords; // The default password for keys in the keystore - protected by the master password. - std::string m_password = asString(h256::random().asBytes()); + std::string m_password; KeyStore m_store; h128 m_key; + std::string m_keysFile = getDataDir("ethereum") + "/keys.info"; }; int main() { KeyManager keyman; + if (keyman.exists()) + keyman.load("foo"); + else + keyman.create("foo"); + auto id = fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0"); - cdebug << "Secret key for " << toUUID(id) << "is" << keyman.secret(id, [](){ return "bar"; }); + keyman.importExisting(id, "bar"); + + cdebug << "Secret key for " << toUUID(id) << "is" << keyman.store().key(id, [](){ return "bar"; }); } #elif 0 From de10fdc403024e721e78fe97341028c16c2f85be Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 May 2015 18:37:18 +0300 Subject: [PATCH 74/87] Fairly complete implementation of KeyManager - now to integrate. --- exp/main.cpp | 128 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 32 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 9b6813ccf..f3b69e7a4 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,10 +70,10 @@ inline std::string toUUID(h128 const& _uuid) { std::string ret = toHex(_uuid.ref class KeyStore { public: - KeyStore() { readKeys(); } + KeyStore() { load(); } ~KeyStore() {} - bytes key(h128 const& _uuid, function const& _pass) + bytes secret(h128 const& _uuid, function const& _pass) { auto rit = m_cached.find(_uuid); if (rit != m_cached.end()) @@ -81,41 +81,55 @@ public: auto it = m_keys.find(_uuid); if (it == m_keys.end()) return bytes(); - bytes key = decrypt(it->second, _pass()); + bytes key = decrypt(it->second.first, _pass()); if (!key.empty()) m_cached[_uuid] = key; return key; } - h128 import(bytes const& _s, std::string const& _pass) + h128 importSecret(bytes const& _s, std::string const& _pass) { h128 r = h128::random(); m_cached[r] = _s; - m_keys[r] = encrypt(_s, _pass); - writeKeys(); + m_keys[r] = make_pair(encrypt(_s, _pass), std::string()); + save(); return r; } + void kill(h128 const& _uuid) + { + m_cached.erase(_uuid); + if (m_keys.count(_uuid)) + { + boost::filesystem::remove(m_keys[_uuid].second); + m_keys.erase(_uuid); + } + } + // Clear any cached keys. void clearCache() const { m_cached.clear(); } private: - void writeKeys(std::string const& _keysPath = getDataDir("web3") + "/keys") + void save(std::string const& _keysPath = getDataDir("web3") + "/keys") { fs::path p(_keysPath); boost::filesystem::create_directories(p); - for (auto const& k: m_keys) + for (auto& k: m_keys) { std::string uuid = toUUID(k.first); + std::string filename = (p / uuid).string() + ".json"; js::mObject v; - v["crypto"] = k.second; + v["crypto"] = k.second.first; v["id"] = uuid; v["version"] = 2; - writeFile((p / uuid).string() + ".json", js::write_string(js::mValue(v), true)); + writeFile(filename, js::write_string(js::mValue(v), true)); + if (!k.second.second.empty() && k.second.second != filename) + boost::filesystem::remove(k.second.second); + k.second.second = filename; } } - void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys") + void load(std::string const& _keysPath = getDataDir("web3") + "/keys") { fs::path p(_keysPath); js::mValue v; @@ -129,7 +143,7 @@ private: js::mObject o = v.get_obj(); int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0; if (version == 2) - m_keys[fromUUID(o["id"].get_str())] = o["crypto"]; + m_keys[fromUUID(o["id"].get_str())] = make_pair(o["crypto"], it->path().string()); else cwarn << "Cannot read key version" << version; } @@ -229,7 +243,7 @@ private: } mutable std::map m_cached; - std::map m_keys; + std::map> m_keys; }; class UnknownPassword: public Exception {}; @@ -237,7 +251,7 @@ class UnknownPassword: public Exception {}; struct KeyInfo { h256 passHash; - std::string name; + std::string info; }; static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); }; @@ -255,7 +269,7 @@ static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()) class KeyManager { public: - KeyManager() {} + KeyManager(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info"): m_keysFile(_keysFile) {} ~KeyManager() {} void setKeysFile(std::string const& _keysFile) { m_keysFile = _keysFile; } @@ -289,7 +303,7 @@ public: m_passwordInfo[(h256)i[0]] = (std::string)i[1]; m_password = (string)s[3]; } - m_cachedPasswords[sha3(m_password)] = m_password; + m_cachedPasswords[hashPassword(m_password)] = m_password; return true; } catch (...) { @@ -312,12 +326,12 @@ public: Secret secret(h128 const& _uuid, function const& _pass = DontKnowThrow) { - return Secret(m_store.key(_uuid, [&](){ + return Secret(m_store.secret(_uuid, [&](){ auto it = m_cachedPasswords.find(m_keyInfo[_uuid].passHash); if (it == m_cachedPasswords.end()) { std::string p = _pass(); - m_cachedPasswords[sha3(p)] = p; + m_cachedPasswords[hashPassword(p)] = p; return p; } else @@ -325,45 +339,89 @@ public: })); } - h128 import(Secret const& _s, std::string const& _pass, string const& _info = std::string(), string const& _passInfo = std::string()) + h128 uuid(Address const& _a) const + { + auto it = m_addrLookup.find(_a); + if (it == m_addrLookup.end()) + return h128(); + return it->second; + } + + Address address(h128 const& _uuid) const + { + for (auto const& i: m_addrLookup) + if (i.second == _uuid) + return i.first; + return Address(); + } + + h128 import(Secret const& _s, string const& _info, std::string const& _pass, string const& _passInfo) { Address addr = KeyPair(_s).address(); - auto passHash = sha3(_pass); + auto passHash = hashPassword(_pass); m_cachedPasswords[passHash] = _pass; m_passwordInfo[passHash] = _passInfo; - auto uuid = m_store.import(_s.asBytes(), _pass); + auto uuid = m_store.importSecret(_s.asBytes(), _pass); m_keyInfo[uuid] = KeyInfo{passHash, _info}; m_addrLookup[addr] = uuid; save(m_keysFile); return uuid; } - h128 import(Secret const& _s, std::string const& _info = std::string()) + h128 import(Secret const& _s, std::string const& _info) { // cache password, remember the key, remember the address - return import(_s, m_password, _info, std::string()); + return import(_s, _info, m_password, std::string()); } - void importExisting(h128 const& _uuid, std::string const& _pass, std::string const& _info = std::string(), std::string const& _passInfo = std::string()) + void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo) { - bytes key = m_store.key(_uuid, [&](){ return _pass; }); + bytes key = m_store.secret(_uuid, [&](){ return _pass; }); if (key.empty()) return; Address a = KeyPair(Secret(key)).address(); - auto passHash = sha3(_pass); + auto passHash = hashPassword(_pass); if (!m_passwordInfo.count(passHash)) m_passwordInfo[passHash] = _passInfo; if (!m_cachedPasswords.count(passHash)) m_cachedPasswords[passHash] = _pass; m_addrLookup[a] = _uuid; m_keyInfo[_uuid].passHash = passHash; - m_keyInfo[_uuid].name = _info; + m_keyInfo[_uuid].info = _info; save(m_keysFile); } + void kill(h128 const& _id) + { + kill(address(_id)); + } + + void kill(Address const& _a) + { + auto id = m_addrLookup[_a]; + m_addrLookup.erase(_a); + m_keyInfo.erase(id); + m_store.kill(id); + } + + std::map keys() const + { + std::map ret; + for (auto const& i: m_addrLookup) + if (m_keyInfo.count(i.second) > 0) + ret[i.first] = m_keyInfo.at(i.second).info; + return ret; + } + KeyStore& store() { return m_store; } private: + h256 hashPassword(std::string const& _pass) const + { + // TODO SECURITY: store this a bit more securely; Scrypt perhaps? + return h256(pbkdf2(_pass, asBytes(m_password), 262144, 32)); + } + // Only use if previously loaded ok. // @returns false if wasn't previously loaded ok. bool save(std::string const& _keysFile) @@ -388,7 +446,7 @@ private: s << 1; s.appendList(m_addrLookup.size()); for (auto const& i: m_addrLookup) - s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].name; + s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].info; s.appendList(m_passwordInfo.size()); for (auto const& i: m_passwordInfo) s.appendList(2) << i.first << i.second; @@ -411,7 +469,7 @@ private: KeyStore m_store; h128 m_key; - std::string m_keysFile = getDataDir("ethereum") + "/keys.info"; + std::string m_keysFile; }; int main() @@ -422,10 +480,16 @@ int main() else keyman.create("foo"); - auto id = fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0"); - keyman.importExisting(id, "bar"); + Address a("9cab1cc4e8fe528267c6c3af664a1adbce810b5f"); + +// keyman.importExisting(fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0"), "{\"name\":\"Gavin Wood - Main identity\"}", "bar", "{\"hint\":\"Not foo.\"}"); +// Address a2 = keyman.address(keyman.import(Secret::random(), "Key with no additional security.")); +// cdebug << toString(a2); + Address a2("19c486071651b2650449ba3c6a807f316a73e8fe"); + + cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; }); + cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); - cdebug << "Secret key for " << toUUID(id) << "is" << keyman.store().key(id, [](){ return "bar"; }); } #elif 0 From 06b483326c3939c9e3d8eb3b4dfa1cffce2756e1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 May 2015 18:46:48 +0300 Subject: [PATCH 75/87] Fix up commit that has ugly verbose messages. --- libethcore/BlockInfo.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 431f98bf8..b720829e6 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -195,6 +195,8 @@ template h256 trieRootOver(unsigned _itemCount, T const& _get return t.root(); } +struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; + void BlockInfo::verifyInternals(bytesConstRef _block) const { RLP root(_block); @@ -212,10 +214,10 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const if (transactionsRoot != t.root())*/ auto txList = root[1]; auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); }); - cnote << "expect trroot " << toString(expectedRoot); + clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); if (transactionsRoot != expectedRoot) BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot)); - cnote << "expect uncleh " << toString(sha3(root[2].data())); + clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); if (sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } From 568e46a32b7ec7b60e006dfcb001f311e3fe832d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 May 2015 18:57:40 +0300 Subject: [PATCH 76/87] Bump. --- libdevcore/Common.cpp | 2 +- libethcore/BlockInfo.cpp | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index d0d153fbf..5f3658030 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -28,7 +28,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.16"; +char const* Version = "0.9.17"; void HasInvariants::checkInvariants() const { diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index b720829e6..e20e88a91 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -201,17 +201,6 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const { RLP root(_block); - /*OverlayDB db; - GenericTrieDB t(&db); - t.init(); - unsigned i = 0; - for (auto const& tr: root[1]) - { - bytes k = rlp(i); - t.insert(&k, tr.data()); - ++i; - } - if (transactionsRoot != t.root())*/ auto txList = root[1]; auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); From 7f6cdce158dca98b03998df0ac911a038fff5656 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 May 2015 19:46:23 +0300 Subject: [PATCH 77/87] Repotted SecretStore and KeyManager. --- exp/main.cpp | 412 +---------------------------------- libdevcore/FixedHash.cpp | 17 +- libdevcore/FixedHash.h | 4 + libdevcrypto/Common.cpp | 2 +- libdevcrypto/SecretStore.cpp | 220 +++++++++++++++++++ libdevcrypto/SecretStore.h | 56 +++++ libethereum/KeyManager.cpp | 203 +++++++++++++++++ libethereum/KeyManager.h | 108 +++++++++ 8 files changed, 612 insertions(+), 410 deletions(-) create mode 100644 libdevcrypto/SecretStore.cpp create mode 100644 libdevcrypto/SecretStore.h create mode 100644 libethereum/KeyManager.cpp create mode 100644 libethereum/KeyManager.h diff --git a/exp/main.cpp b/exp/main.cpp index f3b69e7a4..5fee5cbee 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -42,10 +42,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -64,414 +66,6 @@ namespace fs = boost::filesystem; #if 1 -inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); } -inline std::string toUUID(h128 const& _uuid) { std::string ret = toHex(_uuid.ref()); for (unsigned i: {20, 16, 12, 8}) ret.insert(ret.begin() + i, '-'); return ret; } - -class KeyStore -{ -public: - KeyStore() { load(); } - ~KeyStore() {} - - bytes secret(h128 const& _uuid, function const& _pass) - { - auto rit = m_cached.find(_uuid); - if (rit != m_cached.end()) - return rit->second; - auto it = m_keys.find(_uuid); - if (it == m_keys.end()) - return bytes(); - bytes key = decrypt(it->second.first, _pass()); - if (!key.empty()) - m_cached[_uuid] = key; - return key; - } - - h128 importSecret(bytes const& _s, std::string const& _pass) - { - h128 r = h128::random(); - m_cached[r] = _s; - m_keys[r] = make_pair(encrypt(_s, _pass), std::string()); - save(); - return r; - } - - void kill(h128 const& _uuid) - { - m_cached.erase(_uuid); - if (m_keys.count(_uuid)) - { - boost::filesystem::remove(m_keys[_uuid].second); - m_keys.erase(_uuid); - } - } - - // Clear any cached keys. - void clearCache() const { m_cached.clear(); } - -private: - void save(std::string const& _keysPath = getDataDir("web3") + "/keys") - { - fs::path p(_keysPath); - boost::filesystem::create_directories(p); - for (auto& k: m_keys) - { - std::string uuid = toUUID(k.first); - std::string filename = (p / uuid).string() + ".json"; - js::mObject v; - v["crypto"] = k.second.first; - v["id"] = uuid; - v["version"] = 2; - writeFile(filename, js::write_string(js::mValue(v), true)); - if (!k.second.second.empty() && k.second.second != filename) - boost::filesystem::remove(k.second.second); - k.second.second = filename; - } - } - - void load(std::string const& _keysPath = getDataDir("web3") + "/keys") - { - fs::path p(_keysPath); - js::mValue v; - for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) - if (is_regular_file(it->path())) - { - cdebug << "Reading" << it->path(); - js::read_string(contentsString(it->path().string()), v); - if (v.type() == js::obj_type) - { - js::mObject o = v.get_obj(); - int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0; - if (version == 2) - m_keys[fromUUID(o["id"].get_str())] = make_pair(o["crypto"], it->path().string()); - else - cwarn << "Cannot read key version" << version; - } -// else -// cwarn << "Invalid JSON in key file" << it->path().string(); - } - } - - static js::mValue encrypt(bytes const& _v, std::string const& _pass) - { - js::mObject ret; - - // KDF info - unsigned dklen = 16; - unsigned iterations = 262144; - bytes salt = h256::random().asBytes(); - ret["kdf"] = "pbkdf2"; - { - js::mObject params; - params["prf"] = "hmac-sha256"; - params["c"] = (int)iterations; - params["salt"] = toHex(salt); - params["dklen"] = (int)dklen; - ret["kdfparams"] = params; - } - bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen); - - // cipher info - ret["cipher"] = "aes-128-cbc"; - h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); - h128 iv = h128::random(); - { - js::mObject params; - params["iv"] = toHex(iv.ref()); - ret["cipherparams"] = params; - } - - // cipher text - bytes cipherText = encryptSymNoAuth(key, iv, &_v); - ret["ciphertext"] = toHex(cipherText); - - // and mac. - h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); - ret["mac"] = toHex(mac.ref()); - - return ret; - } - - static bytes decrypt(js::mValue const& _v, std::string const& _pass) - { - js::mObject o = _v.get_obj(); - - // derive key - bytes derivedKey; - if (o["kdf"].get_str() == "pbkdf2") - { - auto params = o["kdfparams"].get_obj(); - if (params["prf"].get_str() != "hmac-sha256") - { - cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported."; - return bytes(); - } - unsigned iterations = params["c"].get_int(); - bytes salt = fromHex(params["salt"].get_str()); - derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int()); - } - else - { - cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; - return bytes(); - } - - bytes cipherText = fromHex(o["ciphertext"].get_str()); - - // check MAC - h256 mac(o["mac"].get_str()); - h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); - if (mac != macExp) - { - cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); - } - - // decrypt - if (o["cipher"].get_str() == "aes-128-cbc") - { - auto params = o["cipherparams"].get_obj(); - h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); - h128 iv(params["iv"].get_str()); - return decryptSymNoAuth(key, iv, &cipherText); - } - else - { - cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported."; - return bytes(); - } - } - - mutable std::map m_cached; - std::map> m_keys; -}; - -class UnknownPassword: public Exception {}; - -struct KeyInfo -{ - h256 passHash; - std::string info; -}; - -static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); }; - -// TODO: This one is specifically for Ethereum, but we can make it generic in due course. -// TODO: hidden-partition style key-store. -/** - * @brief High-level manager of keys for Ethereum. - * Usage: - * - * Call exists() to check whether there is already a database. If so, get the master password from - * the user and call load() with it. If not, get a new master password from the user (get them to type - * it twice and keep some hint around!) and call create() with it. - */ -class KeyManager -{ -public: - KeyManager(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info"): m_keysFile(_keysFile) {} - ~KeyManager() {} - - void setKeysFile(std::string const& _keysFile) { m_keysFile = _keysFile; } - std::string const& keysFile() const { return m_keysFile; } - - bool exists() - { - return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty(); - } - - void create(std::string const& _pass) - { - m_password = asString(h256::random().asBytes()); - save(_pass, m_keysFile); - } - - bool load(std::string const& _pass) - { - try { - bytes salt = contents(m_keysFile + ".salt"); - bytes encKeys = contents(m_keysFile); - m_key = h128(pbkdf2(_pass, salt, 262144, 16)); - bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys); - RLP s(bs); - unsigned version = (unsigned)s[0]; - if (version == 1) - { - for (auto const& i: s[1]) - m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo{(h256)i[2], (std::string)i[3]}; - for (auto const& i: s[2]) - m_passwordInfo[(h256)i[0]] = (std::string)i[1]; - m_password = (string)s[3]; - } - m_cachedPasswords[hashPassword(m_password)] = m_password; - return true; - } - catch (...) { - return false; - } - } - - void resave(std::string const& _pass) - { - save(_pass, m_keysFile); - } - - Secret secret(Address const& _address, function const& _pass = DontKnowThrow) - { - auto it = m_addrLookup.find(_address); - if (it == m_addrLookup.end()) - return Secret(); - return secret(it->second, _pass); - } - - Secret secret(h128 const& _uuid, function const& _pass = DontKnowThrow) - { - return Secret(m_store.secret(_uuid, [&](){ - auto it = m_cachedPasswords.find(m_keyInfo[_uuid].passHash); - if (it == m_cachedPasswords.end()) - { - std::string p = _pass(); - m_cachedPasswords[hashPassword(p)] = p; - return p; - } - else - return it->second; - })); - } - - h128 uuid(Address const& _a) const - { - auto it = m_addrLookup.find(_a); - if (it == m_addrLookup.end()) - return h128(); - return it->second; - } - - Address address(h128 const& _uuid) const - { - for (auto const& i: m_addrLookup) - if (i.second == _uuid) - return i.first; - return Address(); - } - - h128 import(Secret const& _s, string const& _info, std::string const& _pass, string const& _passInfo) - { - Address addr = KeyPair(_s).address(); - auto passHash = hashPassword(_pass); - m_cachedPasswords[passHash] = _pass; - m_passwordInfo[passHash] = _passInfo; - auto uuid = m_store.importSecret(_s.asBytes(), _pass); - m_keyInfo[uuid] = KeyInfo{passHash, _info}; - m_addrLookup[addr] = uuid; - save(m_keysFile); - return uuid; - } - - h128 import(Secret const& _s, std::string const& _info) - { - // cache password, remember the key, remember the address - return import(_s, _info, m_password, std::string()); - } - - void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo) - { - bytes key = m_store.secret(_uuid, [&](){ return _pass; }); - if (key.empty()) - return; - Address a = KeyPair(Secret(key)).address(); - auto passHash = hashPassword(_pass); - if (!m_passwordInfo.count(passHash)) - m_passwordInfo[passHash] = _passInfo; - if (!m_cachedPasswords.count(passHash)) - m_cachedPasswords[passHash] = _pass; - m_addrLookup[a] = _uuid; - m_keyInfo[_uuid].passHash = passHash; - m_keyInfo[_uuid].info = _info; - save(m_keysFile); - } - - void kill(h128 const& _id) - { - kill(address(_id)); - } - - void kill(Address const& _a) - { - auto id = m_addrLookup[_a]; - m_addrLookup.erase(_a); - m_keyInfo.erase(id); - m_store.kill(id); - } - - std::map keys() const - { - std::map ret; - for (auto const& i: m_addrLookup) - if (m_keyInfo.count(i.second) > 0) - ret[i.first] = m_keyInfo.at(i.second).info; - return ret; - } - - KeyStore& store() { return m_store; } - -private: - h256 hashPassword(std::string const& _pass) const - { - // TODO SECURITY: store this a bit more securely; Scrypt perhaps? - return h256(pbkdf2(_pass, asBytes(m_password), 262144, 32)); - } - - // Only use if previously loaded ok. - // @returns false if wasn't previously loaded ok. - bool save(std::string const& _keysFile) - { - if (!m_key) - return false; - save(m_key, _keysFile); - return true; - } - - void save(std::string const& _pass, std::string const& _keysFile) - { - bytes salt = h256::random().asBytes(); - writeFile(_keysFile + ".salt", salt); - auto key = h128(pbkdf2(_pass, salt, 262144, 16)); - save(key, _keysFile); - } - - void save(h128 const& _key, std::string const& _keysFile) - { - RLPStream s(4); - s << 1; - s.appendList(m_addrLookup.size()); - for (auto const& i: m_addrLookup) - s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].info; - s.appendList(m_passwordInfo.size()); - for (auto const& i: m_passwordInfo) - s.appendList(2) << i.first << i.second; - s.append(m_password); - - writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out())); - m_key = _key; - } - - // Ethereum keys. - std::map m_addrLookup; - std::map m_keyInfo; - std::map m_passwordInfo; - - // Passwords that we're storing. - std::map m_cachedPasswords; - - // The default password for keys in the keystore - protected by the master password. - std::string m_password; - - KeyStore m_store; - h128 m_key; - std::string m_keysFile; -}; - int main() { KeyManager keyman; @@ -487,6 +81,8 @@ int main() // cdebug << toString(a2); Address a2("19c486071651b2650449ba3c6a807f316a73e8fe"); + cdebug << keyman.keys(); + cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; }); cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); diff --git a/libdevcore/FixedHash.cpp b/libdevcore/FixedHash.cpp index ae2d77c85..6c2a9a57e 100644 --- a/libdevcore/FixedHash.cpp +++ b/libdevcore/FixedHash.cpp @@ -19,10 +19,25 @@ * @date 2014 */ -#include #include "FixedHash.h" +#include +#include using namespace std; using namespace dev; std::random_device dev::s_fixedHashEngine; + +h128 dev::fromUUID(std::string const& _uuid) +{ + return h128(boost::replace_all_copy(_uuid, "-", "")); +} + +std::string dev::toUUID(h128 const& _uuid) +{ + std::string ret = toHex(_uuid.ref()); + for (unsigned i: {20, 16, 12, 8}) + ret.insert(ret.begin() + i, '-'); + return ret; +} + diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index a5d64f77f..14bc500e6 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -262,6 +262,10 @@ inline h160 left160(h256 const& _t) return ret; } +h128 fromUUID(std::string const& _uuid); + +std::string toUUID(h128 const& _uuid); + inline std::string toString(h256s const& _bs) { std::ostringstream out; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index e4f383a38..a5c176fe6 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -20,6 +20,7 @@ * @date 2014 */ +#include "Common.h" #include #include #include @@ -28,7 +29,6 @@ #include "SHA3.h" #include "FileSystem.h" #include "CryptoPP.h" -#include "Common.h" using namespace std; using namespace dev; using namespace dev::crypto; diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp new file mode 100644 index 000000000..858f2a09f --- /dev/null +++ b/libdevcrypto/SecretStore.cpp @@ -0,0 +1,220 @@ +/* + 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 SecretStore.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "SecretStore.h" +#include +#include +#include +#include +#include +#include +#include "SHA3.h" +#include "FileSystem.h" +using namespace std; +using namespace dev; +namespace js = json_spirit; +namespace fs = boost::filesystem; + +SecretStore::SecretStore() +{ + load(); +} + +SecretStore::~SecretStore() +{ +} + +bytes SecretStore::secret(h128 const& _uuid, function const& _pass) const +{ + auto rit = m_cached.find(_uuid); + if (rit != m_cached.end()) + return rit->second; + auto it = m_keys.find(_uuid); + if (it == m_keys.end()) + return bytes(); + bytes key = decrypt(it->second.first, _pass()); + if (!key.empty()) + m_cached[_uuid] = key; + return key; +} + +h128 SecretStore::importSecret(bytes const& _s, std::string const& _pass) +{ + h128 r = h128::random(); + m_cached[r] = _s; + m_keys[r] = make_pair(encrypt(_s, _pass), std::string()); + save(); + return r; +} + +void SecretStore::kill(h128 const& _uuid) +{ + m_cached.erase(_uuid); + if (m_keys.count(_uuid)) + { + boost::filesystem::remove(m_keys[_uuid].second); + m_keys.erase(_uuid); + } +} + +void SecretStore::clearCache() const +{ + m_cached.clear(); +} + +void SecretStore::save(std::string const& _keysPath) +{ + fs::path p(_keysPath); + boost::filesystem::create_directories(p); + for (auto& k: m_keys) + { + std::string uuid = toUUID(k.first); + std::string filename = (p / uuid).string() + ".json"; + js::mObject v; + js::mValue crypto; + js::read_string(k.second.first, crypto); + v["crypto"] = crypto; + v["id"] = uuid; + v["version"] = 2; + writeFile(filename, js::write_string(js::mValue(v), true)); + if (!k.second.second.empty() && k.second.second != filename) + boost::filesystem::remove(k.second.second); + k.second.second = filename; + } +} + +void SecretStore::load(std::string const& _keysPath) +{ + fs::path p(_keysPath); + js::mValue v; + for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) + if (is_regular_file(it->path())) + { + cdebug << "Reading" << it->path(); + js::read_string(contentsString(it->path().string()), v); + if (v.type() == js::obj_type) + { + js::mObject o = v.get_obj(); + int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0; + if (version == 2) + m_keys[fromUUID(o["id"].get_str())] = make_pair(js::write_string(o["crypto"], false), it->path().string()); + else + cwarn << "Cannot read key version" << version; + } +// else +// cwarn << "Invalid JSON in key file" << it->path().string(); + } +} + +std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass) +{ + js::mObject ret; + + // KDF info + unsigned dklen = 16; + unsigned iterations = 262144; + bytes salt = h256::random().asBytes(); + ret["kdf"] = "pbkdf2"; + { + js::mObject params; + params["prf"] = "hmac-sha256"; + params["c"] = (int)iterations; + params["salt"] = toHex(salt); + params["dklen"] = (int)dklen; + ret["kdfparams"] = params; + } + bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen); + + // cipher info + ret["cipher"] = "aes-128-cbc"; + h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + h128 iv = h128::random(); + { + js::mObject params; + params["iv"] = toHex(iv.ref()); + ret["cipherparams"] = params; + } + + // cipher text + bytes cipherText = encryptSymNoAuth(key, iv, &_v); + ret["ciphertext"] = toHex(cipherText); + + // and mac. + h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + ret["mac"] = toHex(mac.ref()); + + return js::write_string((js::mValue)ret, true); +} + +bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) +{ + js::mObject o; + { + js::mValue ov; + js::read_string(_v, ov); + o = ov.get_obj(); + } + + // derive key + bytes derivedKey; + if (o["kdf"].get_str() == "pbkdf2") + { + auto params = o["kdfparams"].get_obj(); + if (params["prf"].get_str() != "hmac-sha256") + { + cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported."; + return bytes(); + } + unsigned iterations = params["c"].get_int(); + bytes salt = fromHex(params["salt"].get_str()); + derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int()); + } + else + { + cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; + return bytes(); + } + + bytes cipherText = fromHex(o["ciphertext"].get_str()); + + // check MAC + h256 mac(o["mac"].get_str()); + h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + if (mac != macExp) + { + cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); + return bytes(); + } + + // decrypt + if (o["cipher"].get_str() == "aes-128-cbc") + { + auto params = o["cipherparams"].get_obj(); + h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + h128 iv(params["iv"].get_str()); + return decryptSymNoAuth(key, iv, &cipherText); + } + else + { + cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported."; + return bytes(); + } +} diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h new file mode 100644 index 000000000..7f4ae08f1 --- /dev/null +++ b/libdevcrypto/SecretStore.h @@ -0,0 +1,56 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file SecretStore.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include "Common.h" +#include "FileSystem.h" + +namespace dev +{ + +class SecretStore +{ +public: + SecretStore(); + ~SecretStore(); + + bytes secret(h128 const& _uuid, std::function const& _pass) const; + h128 importSecret(bytes const& _s, std::string const& _pass); + void kill(h128 const& _uuid); + + // Clear any cached keys. + void clearCache() const; + +private: + void save(std::string const& _keysPath = getDataDir("web3") + "/keys"); + void load(std::string const& _keysPath = getDataDir("web3") + "/keys"); + static std::string encrypt(bytes const& _v, std::string const& _pass); + static bytes decrypt(std::string const& _v, std::string const& _pass); + + mutable std::map m_cached; + std::map> m_keys; +}; + +} + diff --git a/libethereum/KeyManager.cpp b/libethereum/KeyManager.cpp new file mode 100644 index 000000000..92426289e --- /dev/null +++ b/libethereum/KeyManager.cpp @@ -0,0 +1,203 @@ +/* + 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 KeyManager.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "KeyManager.h" +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +namespace fs = boost::filesystem; + +KeyManager::KeyManager(std::string const& _keysFile): + m_keysFile(_keysFile) +{} + +KeyManager::~KeyManager() +{} + +bool KeyManager::exists() const +{ + return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty(); +} + +void KeyManager::create(std::string const& _pass) +{ + m_password = asString(h256::random().asBytes()); + write(_pass, m_keysFile); +} + +bool KeyManager::load(std::string const& _pass) +{ + try { + bytes salt = contents(m_keysFile + ".salt"); + bytes encKeys = contents(m_keysFile); + m_key = h128(pbkdf2(_pass, salt, 262144, 16)); + bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys); + RLP s(bs); + unsigned version = (unsigned)s[0]; + if (version == 1) + { + for (auto const& i: s[1]) + m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo{(h256)i[2], (std::string)i[3]}; + for (auto const& i: s[2]) + m_passwordInfo[(h256)i[0]] = (std::string)i[1]; + m_password = (string)s[3]; + } + m_cachedPasswords[hashPassword(m_password)] = m_password; + return true; + } + catch (...) { + return false; + } +} + +Secret KeyManager::secret(Address const& _address, function const& _pass) const +{ + auto it = m_addrLookup.find(_address); + if (it == m_addrLookup.end()) + return Secret(); + return secret(it->second, _pass); +} + +Secret KeyManager::secret(h128 const& _uuid, function const& _pass) const +{ + return Secret(m_store.secret(_uuid, [&](){ + auto kit = m_keyInfo.find(_uuid); + if (kit != m_keyInfo.end()) + { + auto it = m_cachedPasswords.find(kit->second.passHash); + if (it != m_cachedPasswords.end()) + return it->second; + } + std::string p = _pass(); + m_cachedPasswords[hashPassword(p)] = p; + return p; + })); +} + +h128 KeyManager::uuid(Address const& _a) const +{ + auto it = m_addrLookup.find(_a); + if (it == m_addrLookup.end()) + return h128(); + return it->second; +} + +Address KeyManager::address(h128 const& _uuid) const +{ + for (auto const& i: m_addrLookup) + if (i.second == _uuid) + return i.first; + return Address(); +} + +h128 KeyManager::import(Secret const& _s, string const& _info, std::string const& _pass, string const& _passInfo) +{ + Address addr = KeyPair(_s).address(); + auto passHash = hashPassword(_pass); + m_cachedPasswords[passHash] = _pass; + m_passwordInfo[passHash] = _passInfo; + auto uuid = m_store.importSecret(_s.asBytes(), _pass); + m_keyInfo[uuid] = KeyInfo{passHash, _info}; + m_addrLookup[addr] = uuid; + write(m_keysFile); + return uuid; +} + +void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo) +{ + bytes key = m_store.secret(_uuid, [&](){ return _pass; }); + if (key.empty()) + return; + Address a = KeyPair(Secret(key)).address(); + auto passHash = hashPassword(_pass); + if (!m_passwordInfo.count(passHash)) + m_passwordInfo[passHash] = _passInfo; + if (!m_cachedPasswords.count(passHash)) + m_cachedPasswords[passHash] = _pass; + m_addrLookup[a] = _uuid; + m_keyInfo[_uuid].passHash = passHash; + m_keyInfo[_uuid].info = _info; + write(m_keysFile); +} + +void KeyManager::kill(Address const& _a) +{ + auto id = m_addrLookup[_a]; + m_addrLookup.erase(_a); + m_keyInfo.erase(id); + m_store.kill(id); +} + +std::map> KeyManager::keys() const +{ + std::map> ret; + for (auto const& i: m_addrLookup) + if (m_keyInfo.count(i.second) > 0) + ret[i.first] = make_pair(m_keyInfo.at(i.second).info, m_passwordInfo.at(m_keyInfo.at(i.second).passHash)); + return ret; +} + +h256 KeyManager::hashPassword(std::string const& _pass) const +{ + // TODO SECURITY: store this a bit more securely; Scrypt perhaps? + return h256(pbkdf2(_pass, asBytes(m_password), 262144, 32)); +} + +bool KeyManager::write(std::string const& _keysFile) const +{ + if (!m_key) + return false; + write(m_key, _keysFile); + return true; +} + +void KeyManager::write(std::string const& _pass, std::string const& _keysFile) const +{ + bytes salt = h256::random().asBytes(); + writeFile(_keysFile + ".salt", salt); + auto key = h128(pbkdf2(_pass, salt, 262144, 16)); + write(key, _keysFile); +} + +void KeyManager::write(h128 const& _key, std::string const& _keysFile) const +{ + RLPStream s(4); + s << 1; + s.appendList(m_addrLookup.size()); + for (auto const& i: m_addrLookup) + if (m_keyInfo.count(i.second)) + { + auto ki = m_keyInfo.at(i.second); + s.appendList(4) << i.first << i.second << ki.passHash << ki.info; + } + s.appendList(m_passwordInfo.size()); + for (auto const& i: m_passwordInfo) + s.appendList(2) << i.first << i.second; + s.append(m_password); + + writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out())); + m_key = _key; +} diff --git a/libethereum/KeyManager.h b/libethereum/KeyManager.h new file mode 100644 index 000000000..fb7c1f51f --- /dev/null +++ b/libethereum/KeyManager.h @@ -0,0 +1,108 @@ +/* + 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 KeyManager.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include + +namespace dev +{ + +class UnknownPassword: public Exception {}; + +struct KeyInfo +{ + h256 passHash; + std::string info; +}; + +static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); }; + +// TODO: This one is specifically for Ethereum, but we can make it generic in due course. +// TODO: hidden-partition style key-store. +/** + * @brief High-level manager of keys for Ethereum. + * Usage: + * + * Call exists() to check whether there is already a database. If so, get the master password from + * the user and call load() with it. If not, get a new master password from the user (get them to type + * it twice and keep some hint around!) and call create() with it. + */ +class KeyManager +{ +public: + KeyManager(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info"); + ~KeyManager(); + + void setKeysFile(std::string const& _keysFile) { m_keysFile = _keysFile; } + std::string const& keysFile() const { return m_keysFile; } + + bool exists() const; + void create(std::string const& _pass); + bool load(std::string const& _pass); + void save(std::string const& _pass) const { write(_pass, m_keysFile); } + + std::map> keys() const; + + h128 uuid(Address const& _a) const; + Address address(h128 const& _uuid) const; + + h128 import(Secret const& _s, std::string const& _info, std::string const& _pass, std::string const& _passInfo); + h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, m_password, std::string()); } + + SecretStore& store() { return m_store; } + void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo); + + Secret secret(Address const& _address, std::function const& _pass = DontKnowThrow) const; + Secret secret(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; + + void kill(h128 const& _id) { kill(address(_id)); } + void kill(Address const& _a); + +private: + h256 hashPassword(std::string const& _pass) const; + + // Only use if previously loaded ok. + // @returns false if wasn't previously loaded ok. + bool write(std::string const& _keysFile) const; + void write(std::string const& _pass, std::string const& _keysFile) const; + void write(h128 const& _key, std::string const& _keysFile) const; + + // Ethereum keys. + std::map m_addrLookup; + std::map m_keyInfo; + std::map m_passwordInfo; + + // Passwords that we're storing. + mutable std::map m_cachedPasswords; + + // The default password for keys in the keystore - protected by the master password. + std::string m_password; + + SecretStore m_store; + mutable h128 m_key; + mutable std::string m_keysFile; +}; + +} From 456872daec8b15f82b52b287fe38e824143413d4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 May 2015 20:33:34 +0300 Subject: [PATCH 78/87] Refactor call/create so they don't need a Secret in preparation for integration of the KeyManager. --- eth/main.cpp | 6 +++ libethereum/Client.h | 1 - libethereum/ClientBase.cpp | 20 ++++---- libethereum/ClientBase.h | 8 ++-- libethereum/Interface.h | 12 +++-- libethereum/KeyManager.h | 2 +- libethereum/Transaction.h | 6 ++- libethereumx/Ethereum.cpp | 2 +- libethereumx/Ethereum.h | 2 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 58 +++++++++++------------ libweb3jsonrpc/WebThreeStubServerBase.h | 7 +-- mix/MixClient.cpp | 48 ++++++++++--------- mix/MixClient.h | 10 ++-- 13 files changed, 99 insertions(+), 83 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index cb051aad1..714cd9ca3 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -124,6 +124,7 @@ void help() << " -R,--rebuild Rebuild the blockchain from the existing database." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl << " -S,--session-secret Set the secret key for use with send command, for this session only." << endl + << " --master Give the master password for the key store." << endl << "Client transacting:" << endl << " -B,--block-fees Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl << " -e,--ether-price Set the ether price in the reference unit e.g. ¢ (default: 30.679)." << endl @@ -546,6 +547,9 @@ int main(int argc, char** argv) string farmURL = "http://127.0.0.1:8080"; unsigned farmRecheckPeriod = 500; + /// Wallet password stuff + string masterPassword; + string configFile = getDataDir() + "/config.rlp"; bytes b = contents(configFile); if (b.size()) @@ -580,6 +584,8 @@ int main(int argc, char** argv) cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl; remotePort = (short)atoi(argv[++i]); } + else if (arg == "--master" && i + 1 < argc) + masterPassword = argv[++i]; else if ((arg == "-I" || arg == "--import") && i + 1 < argc) { mode = OperationMode::Import; diff --git a/libethereum/Client.h b/libethereum/Client.h index e40356f86..674556a6e 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -309,7 +309,6 @@ private: ActivityReport m_report; - // TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables) std::condition_variable m_signalled; Mutex x_signalled; std::atomic m_syncTransactionQueue = {false}; diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 8b3cd416f..cfa271cf6 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -75,17 +75,17 @@ Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes con } // TODO: remove try/catch, allow exceptions -ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff) +ExecutionResult ClientBase::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff) { ExecutionResult ret; try { State temp = asOf(_blockNumber); - Address a = toAddress(_secret); - u256 n = temp.transactionsFrom(a); - Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + u256 n = temp.transactionsFrom(_from); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n); + t.forceSender(_from); if (_ff == FudgeFactor::Lenient) - temp.addBalance(a, (u256)(t.gas() * t.gasPrice() + t.value())); + temp.addBalance(_from, (u256)(t.gas() * t.gasPrice() + t.value())); ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted); } catch (...) @@ -95,19 +95,19 @@ ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, byt return ret; } -ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff) +ExecutionResult ClientBase::create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff) { ExecutionResult ret; try { State temp = asOf(_blockNumber); - Address a = toAddress(_secret); - u256 n = temp.transactionsFrom(a); + u256 n = temp.transactionsFrom(_from); // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); - Transaction t(_value, _gasPrice, _gas, _data, n, _secret); + Transaction t(_value, _gasPrice, _gas, _data, n); + t.forceSender(_from); if (_ff == FudgeFactor::Lenient) - temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value())); + temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted); } catch (...) diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 87888affe..32fd36cce 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -83,11 +83,13 @@ public: virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; /// Makes the given call. Nothing is recorded into the state. - virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override; + virtual ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override; + using Interface::call; /// Makes the given create. Nothing is recorded into the state. - virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override; - + virtual ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override; + using Interface::create; + using Interface::balanceAt; using Interface::countAt; using Interface::stateAt; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index f36d0f2c1..a82595e2d 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -76,13 +76,17 @@ public: virtual void flushTransactions() = 0; /// Makes the given call. Nothing is recorded into the state. - virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0; - ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return call(_secret, _value, _dest, _data, _gas, _gasPrice, m_default, _ff); } + virtual ExecutionResult call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0; + ExecutionResult call(Address const& _from, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return call(_from, _value, _dest, _data, _gas, _gasPrice, m_default, _ff); } + ExecutionResult call(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) { return call(toAddress(_secret), _value, _dest, _data, _gas, _gasPrice, _blockNumber, _ff); } + ExecutionResult call(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, FudgeFactor _ff = FudgeFactor::Strict) { return call(toAddress(_secret), _value, _dest, _data, _gas, _gasPrice, _ff); } /// Does the given creation. Nothing is recorded into the state. /// @returns the pair of the Address of the created contract together with its code. - virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0; - ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return create(_secret, _value, _data, _gas, _gasPrice, m_default, _ff); } + virtual ExecutionResult create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0; + ExecutionResult create(Address const& _from, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return create(_from, _value, _data, _gas, _gasPrice, m_default, _ff); } + ExecutionResult create(Secret const& _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) { return create(toAddress(_secret), _value, _data, _gas, _gasPrice, _blockNumber, _ff); } + ExecutionResult create(Secret const& _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, FudgeFactor _ff = FudgeFactor::Strict) { return create(toAddress(_secret), _value, _data, _gas, _gasPrice, _ff); } /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. virtual ImportResult injectTransaction(bytes const& _rlp) = 0; diff --git a/libethereum/KeyManager.h b/libethereum/KeyManager.h index fb7c1f51f..223d60670 100644 --- a/libethereum/KeyManager.h +++ b/libethereum/KeyManager.h @@ -37,7 +37,7 @@ struct KeyInfo std::string info; }; -static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); }; +static const auto DontKnowThrow = [](){ throw UnknownPassword(); return std::string(); }; // TODO: This one is specifically for Ethereum, but we can make it generic in due course. // TODO: hidden-partition style key-store. diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 2b11c52d6..78852b7b8 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -111,10 +111,10 @@ public: Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce, Secret const& _secret): m_type(ContractCreation), m_nonce(_nonce), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); } /// Constructs an unsigned message-call transaction. - Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data): m_type(MessageCall), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} + Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce = 0): m_type(MessageCall), m_nonce(_nonce), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} /// Constructs an unsigned contract-creation transaction. - Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data): m_type(ContractCreation), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} + Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = 0): m_type(ContractCreation), m_nonce(_nonce), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} /// Constructs a transaction from the given RLP. explicit Transaction(bytesConstRef _rlp, CheckTransaction _checkSig); @@ -132,6 +132,8 @@ public: Address const& sender() const; /// Like sender() but will never throw. @returns a null Address if the signature is invalid. Address const& safeSender() const noexcept; + /// Force the sender to a particular value. This will result in an invalid transaction RLP. + void forceSender(Address const& _a) { m_sender = _a; } /// @returns true if transaction is non-null. explicit operator bool() const { return m_type != NullTransaction; } diff --git a/libethereumx/Ethereum.cpp b/libethereumx/Ethereum.cpp index 54b698646..8ab4243a1 100644 --- a/libethereumx/Ethereum.cpp +++ b/libethereumx/Ethereum.cpp @@ -87,7 +87,7 @@ void Ethereum::submitTransaction(Secret _secret, u256 _value, Address _dest, byt { } -bytes Ethereum::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +bytes Ethereum::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { return bytes(); } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 15f00f4ae..0e81b8e0c 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -75,7 +75,7 @@ public: void flushTransactions(); /// Makes the given call. Nothing is recorded into the state. - bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + bytes call(Address const& _from, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); // Informational stuff diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 3f0566626..244f199d1 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -298,16 +298,16 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message } WebThreeStubServerBase::WebThreeStubServerBase(AbstractServerConnector& _conn, vector const& _accounts): - AbstractWebThreeStubServer(_conn), m_accounts(make_shared(bind(&WebThreeStubServerBase::client, this))) + AbstractWebThreeStubServer(_conn), m_ethAccounts(make_shared(bind(&WebThreeStubServerBase::client, this))) { - m_accounts->setAccounts(_accounts); + m_ethAccounts->setAccounts(_accounts); } void WebThreeStubServerBase::setIdentities(vector const& _ids) { - m_ids.clear(); + m_shhIds.clear(); for (auto i: _ids) - m_ids[i.pub()] = i.secret(); + m_shhIds[i.pub()] = i.secret(); } string WebThreeStubServerBase::web3_sha3(string const& _param1) @@ -353,7 +353,7 @@ string WebThreeStubServerBase::eth_gasPrice() Json::Value WebThreeStubServerBase::eth_accounts() { Json::Value ret(Json::arrayValue); - for (auto const& i: m_accounts->getAllAccounts()) + for (auto const& i: m_ethAccounts->getAllAccounts()) ret.append(toJS(i)); return ret; } @@ -499,7 +499,7 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json) TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts->getDefaultTransactAccount(); + t.from = m_ethAccounts->getDefaultTransactAccount(); if (t.creation) ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));; if (t.gasPrice == UndefinedU256) @@ -507,9 +507,9 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json) if (t.gas == UndefinedU256) t.gas = min(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice); - if (m_accounts->isRealAccount(t.from)) + if (m_ethAccounts->isRealAccount(t.from)) authenticate(t, false); - else if (m_accounts->isProxyAccount(t.from)) + else if (m_ethAccounts->isProxyAccount(t.from)) authenticate(t, true); return ret; @@ -528,7 +528,7 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json) TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts->getDefaultTransactAccount(); + t.from = m_ethAccounts->getDefaultTransactAccount(); if (t.creation) ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));; if (t.gasPrice == UndefinedU256) @@ -536,9 +536,9 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json) if (t.gas == UndefinedU256) t.gas = min(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice); - if (m_accounts->isRealAccount(t.from)) + if (m_ethAccounts->isRealAccount(t.from)) authenticate(t, false); - else if (m_accounts->isProxyAccount(t.from)) + else if (m_ethAccounts->isProxyAccount(t.from)) authenticate(t, true); return toJS((t.creation ? Transaction(t.value, t.gasPrice, t.gas, t.data) : Transaction(t.value, t.gasPrice, t.gas, t.to, t.data)).sha3(WithoutSignature)); @@ -579,7 +579,7 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const& { TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts->getDefaultTransactAccount(); + t.from = m_ethAccounts->getDefaultTransactAccount(); // if (!m_accounts->isRealAccount(t.from)) // return ret; if (t.gasPrice == UndefinedU256) @@ -587,7 +587,7 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const& if (t.gas == UndefinedU256) t.gas = client()->gasLimitRemaining(); - return toJS(client()->call(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice, jsToBlockNumber(_blockNumber), FudgeFactor::Lenient).output); + return toJS(client()->call(m_ethAccounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice, jsToBlockNumber(_blockNumber), FudgeFactor::Lenient).output); } catch (...) { @@ -879,7 +879,7 @@ string WebThreeStubServerBase::eth_register(string const& _address) { try { - return toJS(m_accounts->addProxyAccount(jsToAddress(_address))); + return toJS(m_ethAccounts->addProxyAccount(jsToAddress(_address))); } catch (...) { @@ -891,7 +891,7 @@ bool WebThreeStubServerBase::eth_unregister(string const& _accountId) { try { - return m_accounts->removeProxyAccount(jsToInt(_accountId)); + return m_ethAccounts->removeProxyAccount(jsToInt(_accountId)); } catch (...) { @@ -906,9 +906,9 @@ Json::Value WebThreeStubServerBase::eth_fetchQueuedTransactions(string const& _a auto id = jsToInt(_accountId); Json::Value ret(Json::arrayValue); // TODO: throw an error on no account with given id - for (TransactionSkeleton const& t: m_accounts->getQueuedTransactions(id)) + for (TransactionSkeleton const& t: m_ethAccounts->getQueuedTransactions(id)) ret.append(toJson(t)); - m_accounts->clearQueue(id); + m_ethAccounts->clearQueue(id); return ret; } catch (...) @@ -934,11 +934,11 @@ bool WebThreeStubServerBase::shh_post(Json::Value const& _json) { shh::Message m = toMessage(_json); Secret from; - if (m.from() && m_ids.count(m.from())) + if (m.from() && m_shhIds.count(m.from())) { cwarn << "Silently signing message from identity" << m.from() << ": User validation hook goes here."; // TODO: insert validification hook here. - from = m_ids[m.from()]; + from = m_shhIds[m.from()]; } face()->inject(toSealed(_json, m, from)); @@ -953,7 +953,7 @@ bool WebThreeStubServerBase::shh_post(Json::Value const& _json) string WebThreeStubServerBase::shh_newIdentity() { KeyPair kp = KeyPair::create(); - m_ids[kp.pub()] = kp.secret(); + m_shhIds[kp.pub()] = kp.secret(); return toJS(kp.pub()); } @@ -961,7 +961,7 @@ bool WebThreeStubServerBase::shh_hasIdentity(string const& _identity) { try { - return m_ids.count(jsToPublic(_identity)) > 0; + return m_shhIds.count(jsToPublic(_identity)) > 0; } catch (...) { @@ -1021,7 +1021,7 @@ Json::Value WebThreeStubServerBase::shh_getFilterChanges(string const& _filterId int id = jsToInt(_filterId); auto pub = m_shhWatches[id]; - if (!pub || m_ids.count(pub)) + if (!pub || m_shhIds.count(pub)) for (h256 const& h: face()->checkWatch(id)) { auto e = face()->envelope(h); @@ -1029,7 +1029,7 @@ Json::Value WebThreeStubServerBase::shh_getFilterChanges(string const& _filterId if (pub) { cwarn << "Silently decrypting message from identity" << pub << ": User validation hook goes here."; - m = e.open(face()->fullTopic(id), m_ids[pub]); + m = e.open(face()->fullTopic(id), m_shhIds[pub]); } else m = e.open(face()->fullTopic(id)); @@ -1054,7 +1054,7 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId) int id = jsToInt(_filterId); auto pub = m_shhWatches[id]; - if (!pub || m_ids.count(pub)) + if (!pub || m_shhIds.count(pub)) for (h256 const& h: face()->watchMessages(id)) { auto e = face()->envelope(h); @@ -1062,7 +1062,7 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId) if (pub) { cwarn << "Silently decrypting message from identity" << pub << ": User validation hook goes here."; - m = e.open(face()->fullTopic(id), m_ids[pub]); + m = e.open(face()->fullTopic(id), m_shhIds[pub]); } else m = e.open(face()->fullTopic(id)); @@ -1081,14 +1081,14 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId) void WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool _toProxy) { if (_toProxy) - m_accounts->queueTransaction(_t); + m_ethAccounts->queueTransaction(_t); else if (_t.to) - client()->submitTransaction(m_accounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); + client()->submitTransaction(m_ethAccounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); else - client()->submitTransaction(m_accounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice); + client()->submitTransaction(m_ethAccounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice); } void WebThreeStubServerBase::setAccounts(const vector& _accounts) { - m_accounts->setAccounts(_accounts); + m_ethAccounts->setAccounts(_accounts); } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 3166eefad..425e6567e 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -136,7 +136,7 @@ public: void setAccounts(std::vector const& _accounts); void setIdentities(std::vector const& _ids); - std::map const& ids() const { return m_ids; } + std::map const& ids() const { return m_shhIds; } protected: virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); @@ -147,9 +147,10 @@ protected: virtual dev::WebThreeNetworkFace* network() = 0; virtual dev::WebThreeStubDatabaseFace* db() = 0; - std::map m_ids; + std::shared_ptr m_ethAccounts; + + std::map m_shhIds; std::map m_shhWatches; - std::shared_ptr m_accounts; }; } //namespace dev diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 1f309c5af..94bd0d71f 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -98,17 +98,20 @@ void MixClient::resetState(std::unordered_map const& _accounts m_executions.clear(); } -Transaction MixClient::replaceGas(Transaction const& _t, Secret const& _secret, u256 const& _gas) +Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas) { + Transaction ret; if (_t.isCreation()) - return Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret); + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce()); else - return Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret); + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce()); + ret.forceSender(_t.safeSender()); + return ret; } -void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) +void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto) { - Transaction t = _gasAuto ? replaceGas(_t, _secret, m_state.gasLimitRemaining()) : _t; + Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; bytes rlp = t.rlp(); // do debugging run first @@ -219,7 +222,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c // execute on a state if (!_call) { - t = _gasAuto ? replaceGas(_t, _secret, d.gasUsed) : _t; + t = _gasAuto ? replaceGas(_t, d.gasUsed) : _t; er =_state.execute(lastHashes, t); if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); @@ -282,7 +285,7 @@ void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, by WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - executeTransaction(t, m_state, false, _gasAuto, _secret); + executeTransaction(t, m_state, false, _gasAuto); } Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto) @@ -290,23 +293,23 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); - executeTransaction(t, m_state, false, _gasAuto, _secret); + executeTransaction(t, m_state, false, _gasAuto); Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); return address; } -dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff) +dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff) { (void)_blockNumber; - Address a = toAddress(_secret); State temp = asOf(eth::PendingBlock); - u256 n = temp.transactionsFrom(a); - Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + u256 n = temp.transactionsFrom(_from); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n); + t.forceSender(_from); if (_ff == FudgeFactor::Lenient) - temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value())); + temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); bytes rlp = t.rlp(); WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, temp, true, _gasAuto, _secret); + executeTransaction(t, temp, true, _gasAuto); return lastExecution().result; } @@ -320,28 +323,27 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons return submitTransaction(_secret, _endowment, _init, _gas, _gasPrice, false); } -dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) +dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) { - return call(_secret, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff); + return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff); } -dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) +dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) { (void)_blockNumber; u256 n; - Address a = toAddress(_secret); State temp; { ReadGuard lr(x_state); temp = asOf(eth::PendingBlock); - n = temp.transactionsFrom(a); + n = temp.transactionsFrom(_from); } - Transaction t(_value, _gasPrice, _gas, _data, n, _secret); + Transaction t(_value, _gasPrice, _gas, _data, n); + t.forceSender(_from); if (_ff == FudgeFactor::Lenient) - temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value())); - bytes rlp = t.rlp(); + temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, temp, true, false, _secret); + executeTransaction(t, temp, true, false); return lastExecution().result; } diff --git a/mix/MixClient.h b/mix/MixClient.h index 99637720a..f7687c488 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -55,12 +55,12 @@ public: void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override; - dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; - dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; + dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; + dev::eth::ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto); Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto); - dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); + dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); void setAddress(Address _us) override; void startMining() override; @@ -87,9 +87,9 @@ protected: virtual void prepareForTransaction() override {} private: - void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret); + void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto); void noteChanged(h256Set const& _filters); - dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::Secret const& _secret, dev::u256 const& _gas); + dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas); eth::State m_state; eth::State m_startState; From da90ad998730640fbdad4d4ef7a21138586a3c1d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 9 May 2015 20:42:19 +0300 Subject: [PATCH 79/87] Remove unnecessary secret key ask. --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 244f199d1..12486d529 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -587,7 +587,7 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const& if (t.gas == UndefinedU256) t.gas = client()->gasLimitRemaining(); - return toJS(client()->call(m_ethAccounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice, jsToBlockNumber(_blockNumber), FudgeFactor::Lenient).output); + return toJS(client()->call(t.from, t.value, t.to, t.data, t.gas, t.gasPrice, jsToBlockNumber(_blockNumber), FudgeFactor::Lenient).output); } catch (...) { From 10aec68f63132c57091a995dae15aeb5df551b7d Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 9 May 2015 21:52:21 +0200 Subject: [PATCH 80/87] fixed transaction signatures --- mix/MixClient.cpp | 39 +++++++++++++++++++++++---------------- mix/MixClient.h | 4 ++-- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 94bd0d71f..09fed6fc6 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -98,22 +98,30 @@ void MixClient::resetState(std::unordered_map const& _accounts m_executions.clear(); } -Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas) +Transaction MixClient::replaceGas(Transaction const& _t, Secret const& _secret, u256 const& _gas) { Transaction ret; - if (_t.isCreation()) - ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce()); + if (_secret) + { + if (_t.isCreation()) + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret); + else + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret); + } else - ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce()); - ret.forceSender(_t.safeSender()); + { + if (_t.isCreation()) + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce()); + else + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce()); + ret.forceSender(_t.safeSender()); + } return ret; } -void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto) +void MixClient::executeTransaction(Transaction const& _t, Secret const& _secret, State& _state, bool _call, bool _gasAuto) { - Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; - bytes rlp = t.rlp(); - + Transaction t = _gasAuto ? replaceGas(_t, Secret(), m_state.gasLimitRemaining()) : _t; // do debugging run first LastHashes lastHashes(256); lastHashes[0] = bc().numberHash(bc().number()); @@ -123,7 +131,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c State execState = _state; execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation Executive execution(execState, lastHashes, 0); - execution.initialize(&rlp); + execution.initialize(t); execution.execute(); std::vector machineStates; std::vector levels; @@ -222,7 +230,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c // execute on a state if (!_call) { - t = _gasAuto ? replaceGas(_t, d.gasUsed) : _t; + t = _gasAuto ? replaceGas(_t, _secret, d.gasUsed) : _t; er =_state.execute(lastHashes, t); if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); @@ -285,7 +293,7 @@ void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, by WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - executeTransaction(t, m_state, false, _gasAuto); + executeTransaction(t, _secret, m_state, false, _gasAuto); } Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto) @@ -293,7 +301,7 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); - executeTransaction(t, m_state, false, _gasAuto); + executeTransaction(t, _secret, m_state, false, _gasAuto); Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); return address; } @@ -307,9 +315,8 @@ dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Add t.forceSender(_from); if (_ff == FudgeFactor::Lenient) temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); - bytes rlp = t.rlp(); WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, temp, true, _gasAuto); + executeTransaction(t, Secret(), temp, true, _gasAuto); return lastExecution().result; } @@ -343,7 +350,7 @@ dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, b if (_ff == FudgeFactor::Lenient) temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, temp, true, false); + executeTransaction(t, Secret(), temp, true, false); return lastExecution().result; } diff --git a/mix/MixClient.h b/mix/MixClient.h index f7687c488..5988286d0 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -87,9 +87,9 @@ protected: virtual void prepareForTransaction() override {} private: - void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto); + void executeTransaction(dev::eth::Transaction const& _t, dev::Secret const& _secret, eth::State& _state, bool _call, bool _gasAuto); void noteChanged(h256Set const& _filters); - dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas); + dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::Secret const& _secret, dev::u256 const& _gas); eth::State m_state; eth::State m_startState; From b3aeb7bb277dfb9362ff9a95447faa0f3b3c0419 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 10 May 2015 10:12:14 +0200 Subject: [PATCH 81/87] Prevent socket from closing due to attempt to send to bad address. --- libp2p/UDP.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 97136ee43..4cab9b22d 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -223,10 +223,15 @@ void UDPSocket::doWrite() const UDPDatagram& datagram = m_sendQ[0]; auto self(UDPSocket::shared_from_this()); - m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t) + bi::udp::endpoint endpoint(datagram.endpoint()); + m_socket.async_send_to(boost::asio::buffer(datagram.data), endpoint, [this, self, endpoint](boost::system::error_code _ec, std::size_t) { - if (_ec || m_closed) + if (m_closed) return disconnectWithError(_ec); + else if (_ec != boost::system::errc::success && + _ec != boost::system::errc::address_not_available && + _ec != boost::system::errc::host_unreachable) + return disconnectWithError(_ec); // 49: can't assign requested address else { Guard l(x_sendQ); From b47431a328889adde92d04dd5732a9db1edccb82 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 10 May 2015 10:17:13 +0200 Subject: [PATCH 82/87] remove misplaced comment --- libp2p/UDP.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 4cab9b22d..f6a4842a9 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -229,9 +229,9 @@ void UDPSocket::doWrite() if (m_closed) return disconnectWithError(_ec); else if (_ec != boost::system::errc::success && - _ec != boost::system::errc::address_not_available && - _ec != boost::system::errc::host_unreachable) - return disconnectWithError(_ec); // 49: can't assign requested address + _ec != boost::system::errc::address_not_available && + _ec != boost::system::errc::host_unreachable) + return disconnectWithError(_ec); else { Guard l(x_sendQ); From 9071de1133439bebb7f706b34c53a943cf448ae6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 10 May 2015 13:45:36 +0300 Subject: [PATCH 83/87] Build fixes. --- libethereum/KeyManager.cpp | 2 +- libethereum/KeyManager.h | 2 ++ libsolidity/ASTPrinter.h | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libethereum/KeyManager.cpp b/libethereum/KeyManager.cpp index 92426289e..15f767c88 100644 --- a/libethereum/KeyManager.cpp +++ b/libethereum/KeyManager.cpp @@ -60,7 +60,7 @@ bool KeyManager::load(std::string const& _pass) if (version == 1) { for (auto const& i: s[1]) - m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo{(h256)i[2], (std::string)i[3]}; + m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo((h256)i[2], (std::string)i[3]); for (auto const& i: s[2]) m_passwordInfo[(h256)i[0]] = (std::string)i[1]; m_password = (string)s[3]; diff --git a/libethereum/KeyManager.h b/libethereum/KeyManager.h index 223d60670..9cb22e5b3 100644 --- a/libethereum/KeyManager.h +++ b/libethereum/KeyManager.h @@ -33,6 +33,8 @@ class UnknownPassword: public Exception {}; struct KeyInfo { + KeyInfo() = default; + KeyInfo(h256 const& _passHash, std::string const& _info): passHash(_passHash), info(_info) {} h256 passHash; std::string info; }; diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index dabf6470a..25678c176 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -42,7 +42,7 @@ public: ASTPrinter( ASTNode const& _ast, std::string const& _source = std::string(), - StructuralGasEstimator::ASTGasConsumption const& _gasCosts = {} + StructuralGasEstimator::ASTGasConsumption const& _gasCosts = StructuralGasEstimator::ASTGasConsumption() ); /// Output the string representation of the AST to _stream. void print(std::ostream& _stream); From cd1dc2f5ebaad6e3cc8f6e3d9f5f28f70c5ec5e7 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 10 May 2015 20:27:07 +0200 Subject: [PATCH 84/87] fix and add guards --- libp2p/NodeTable.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index c3215da71..e926356b7 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -81,7 +81,8 @@ shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relati { shared_ptr ret(new NodeEntry(m_node, _node.id, _node.endpoint)); ret->pending = false; - m_nodes[_node.id] = ret; + DEV_GUARDED(x_nodes) + m_nodes[_node.id] = ret; noteActiveNode(_node.id, _node.endpoint); return ret; } @@ -101,14 +102,13 @@ shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relati return move(shared_ptr()); } - { - Guard ln(x_nodes); + DEV_GUARDED(x_nodes) if (m_nodes.count(_node.id)) return m_nodes[_node.id]; - } shared_ptr ret(new NodeEntry(m_node, _node.id, _node.endpoint)); - m_nodes[_node.id] = ret; + DEV_GUARDED(x_nodes) + m_nodes[_node.id] = ret; clog(NodeTableConnect) << "addNode pending for" << _node.endpoint; ping(_node.endpoint); return ret; @@ -186,7 +186,8 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrendpoint, _node); p.sign(m_secret); - m_findNodeTimeout.push_back(make_pair(r->id, chrono::steady_clock::now())); + DEV_GUARDED(x_findNodeTimeout) + m_findNodeTimeout.push_back(make_pair(r->id, chrono::steady_clock::now())); m_socketPointer->send(p); } @@ -447,17 +448,17 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes { if (auto n = nodeEntry(nodeid)) n->pending = false; - else if (m_pubkDiscoverPings.count(_from.address())) + else { + DEV_GUARDED(x_pubkDiscoverPings) { - Guard l(x_pubkDiscoverPings); + if (!m_pubkDiscoverPings.count(_from.address())) + return; // unsolicited pong; don't note node as active m_pubkDiscoverPings.erase(_from.address()); } if (!haveNode(nodeid)) addNode(Node(nodeid, NodeIPEndpoint(_from.address(), _from.port(), _from.port()))); } - else - return; // unsolicited pong; don't note node as active } // update our endpoint address and UDP port @@ -473,14 +474,15 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes { bool expected = false; auto now = chrono::steady_clock::now(); - m_findNodeTimeout.remove_if([&](NodeIdTimePoint const& t) - { - if (t.first == nodeid && now - t.second < c_reqTimeout) - expected = true; - else if (t.first == nodeid) - return true; - return false; - }); + DEV_GUARDED(x_findNodeTimeout) + m_findNodeTimeout.remove_if([&](NodeIdTimePoint const& t) + { + if (t.first == nodeid && now - t.second < c_reqTimeout) + expected = true; + else if (t.first == nodeid) + return true; + return false; + }); if (!expected) { From a9d9afb0426b39ac360bb374ed92b619b969afe2 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 10 May 2015 23:37:10 +0200 Subject: [PATCH 85/87] Log errors instead of disconnecting socket. --- libp2p/UDP.cpp | 4 ++++ libp2p/UDP.h | 31 ++++++++++++++++--------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index eeb3a0b1a..9f89d9ad0 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -20,9 +20,13 @@ */ #include "UDP.h" +using namespace std; using namespace dev; using namespace dev::p2p; +const char* RLPXWarn::name() { return "!X!"; } +const char* RLPXNote::name() { return "-X-"; } + h256 RLPXDatagramFace::sign(Secret const& _k) { assert(packetType()); diff --git a/libp2p/UDP.h b/libp2p/UDP.h index f6a4842a9..5058457e5 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "Common.h" namespace ba = boost::asio; @@ -40,6 +41,9 @@ namespace dev namespace p2p { +struct RLPXWarn: public LogChannel { static const char* name(); static const int verbosity = 0; }; +struct RLPXNote: public LogChannel { static const char* name(); static const int verbosity = 1; }; + /** * UDP Datagram * @todo make data protected/functional @@ -203,11 +207,11 @@ void UDPSocket::doRead() auto self(UDPSocket::shared_from_this()); m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) { - // ASIO Safety: It is possible that ASIO will call lambda w/o an error - // and after the socket has been disconnected. Checking m_closed - // guarantees that m_host will not be called after disconnect(). - if (_ec || m_closed) + if (m_closed) return disconnectWithError(_ec); + + if (_ec != boost::system::errc::success) + clog(NetWarn) << "Receiving UDP message failed. " << _ec.value() << ":" << _ec.message(); assert(_len); m_host.onReceived(this, m_recvEndpoint, bytesConstRef(m_recvData.data(), _len)); @@ -228,17 +232,14 @@ void UDPSocket::doWrite() { if (m_closed) return disconnectWithError(_ec); - else if (_ec != boost::system::errc::success && - _ec != boost::system::errc::address_not_available && - _ec != boost::system::errc::host_unreachable) - return disconnectWithError(_ec); - else - { - Guard l(x_sendQ); - m_sendQ.pop_front(); - if (m_sendQ.empty()) - return; - } + + if (_ec != boost::system::errc::success) + clog(NetWarn) << "Failed delivering UDP message. " << _ec.value() << ":" << _ec.message(); + + Guard l(x_sendQ); + m_sendQ.pop_front(); + if (m_sendQ.empty()) + return; doWrite(); }); } From f315243787a6df188af82faa5e4ede0395567d3d Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 10 May 2015 23:42:51 +0200 Subject: [PATCH 86/87] Ignore empty UDP messages (likely when udp/icmp error is received). --- libp2p/UDP.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 5058457e5..b09d556e7 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -213,8 +213,8 @@ void UDPSocket::doRead() if (_ec != boost::system::errc::success) clog(NetWarn) << "Receiving UDP message failed. " << _ec.value() << ":" << _ec.message(); - assert(_len); - m_host.onReceived(this, m_recvEndpoint, bytesConstRef(m_recvData.data(), _len)); + if (_len) + m_host.onReceived(this, m_recvEndpoint, bytesConstRef(m_recvData.data(), _len)); doRead(); }); } From 9b80352a7c4549c123dbac621e8a6609b0f31961 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 11 May 2015 07:45:05 +0200 Subject: [PATCH 87/87] made _secret parameter optional --- mix/MixClient.cpp | 16 ++++++++-------- mix/MixClient.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 09fed6fc6..cac208ba4 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -98,7 +98,7 @@ void MixClient::resetState(std::unordered_map const& _accounts m_executions.clear(); } -Transaction MixClient::replaceGas(Transaction const& _t, Secret const& _secret, u256 const& _gas) +Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secret const& _secret) { Transaction ret; if (_secret) @@ -119,9 +119,9 @@ Transaction MixClient::replaceGas(Transaction const& _t, Secret const& _secret, return ret; } -void MixClient::executeTransaction(Transaction const& _t, Secret const& _secret, State& _state, bool _call, bool _gasAuto) +void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) { - Transaction t = _gasAuto ? replaceGas(_t, Secret(), m_state.gasLimitRemaining()) : _t; + Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; // do debugging run first LastHashes lastHashes(256); lastHashes[0] = bc().numberHash(bc().number()); @@ -230,7 +230,7 @@ void MixClient::executeTransaction(Transaction const& _t, Secret const& _secret, // execute on a state if (!_call) { - t = _gasAuto ? replaceGas(_t, _secret, d.gasUsed) : _t; + t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; er =_state.execute(lastHashes, t); if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); @@ -293,7 +293,7 @@ void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, by WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - executeTransaction(t, _secret, m_state, false, _gasAuto); + executeTransaction(t, m_state, false, _gasAuto, _secret); } Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto) @@ -301,7 +301,7 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); - executeTransaction(t, _secret, m_state, false, _gasAuto); + executeTransaction(t, m_state, false, _gasAuto, _secret); Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); return address; } @@ -316,7 +316,7 @@ dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Add if (_ff == FudgeFactor::Lenient) temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, Secret(), temp, true, _gasAuto); + executeTransaction(t, temp, true, _gasAuto); return lastExecution().result; } @@ -350,7 +350,7 @@ dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, b if (_ff == FudgeFactor::Lenient) temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, Secret(), temp, true, false); + executeTransaction(t, temp, true, false); return lastExecution().result; } diff --git a/mix/MixClient.h b/mix/MixClient.h index 5988286d0..2c6734234 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -87,9 +87,9 @@ protected: virtual void prepareForTransaction() override {} private: - void executeTransaction(dev::eth::Transaction const& _t, dev::Secret const& _secret, eth::State& _state, bool _call, bool _gasAuto); + void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret = dev::Secret()); void noteChanged(h256Set const& _filters); - dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::Secret const& _secret, dev::u256 const& _gas); + dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas, dev::Secret const& _secret = dev::Secret()); eth::State m_state; eth::State m_startState;