Browse Source

Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

cl-refactor
Gav Wood 10 years ago
parent
commit
a9c7f79b05
  1. 134
      CMakeLists.txt
  2. 2
      alethzero/MainWin.cpp
  3. 2
      eth/CMakeLists.txt
  4. 11
      extdep/getstuff.bat
  5. 207
      libevmcore/Assembly.cpp
  6. 20
      libevmcore/Assembly.h
  7. 1
      libevmcore/CMakeLists.txt
  8. 260
      libevmcore/ControlFlowGraph.cpp
  9. 108
      libevmcore/ControlFlowGraph.h
  10. 19
      libevmcore/SemanticInformation.cpp
  11. 1
      libevmcore/SemanticInformation.h
  12. 1
      liblll/CMakeLists.txt
  13. 16
      libp2p/Common.cpp
  14. 33
      libp2p/Common.h
  15. 147
      libp2p/Host.cpp
  16. 7
      libp2p/Host.h
  17. 61
      libp2p/NodeTable.cpp
  18. 63
      libp2p/NodeTable.h
  19. 2
      libp2p/Peer.cpp
  20. 5
      libp2p/Peer.h
  21. 12
      libp2p/Session.cpp
  22. 56
      libsolidity/AST.cpp
  23. 5
      libsolidity/AST.h
  24. 1
      libsolidity/Compiler.cpp
  25. 5
      libsolidity/Compiler.h
  26. 6
      libsolidity/CompilerContext.h
  27. 18
      libsolidity/CompilerStack.cpp
  28. 7
      libsolidity/CompilerStack.h
  29. 16
      libsolidity/LValue.cpp
  30. 4
      libwebthree/WebThree.cpp
  31. 2
      mix/ClientModel.cpp
  32. 2
      mix/CodeHighlighter.cpp
  33. 20
      mix/CodeModel.cpp
  34. 2
      mix/ContractCallDataEncoder.cpp
  35. 3
      mix/FileIo.cpp
  36. 3
      mix/MixClient.cpp
  37. 14
      mix/qml/WebPreview.qml
  38. 4
      mix/qml/html/cm/errorannotation.js
  39. 10
      mix/test/qml/TestMain.qml
  40. 5
      mix/test/qml/js/TestDebugger.js
  41. 10
      mix/test/qml/js/TestMiner.js
  42. 4
      mix/test/qml/js/TestProject.js
  43. 26
      solc/CommandLineInterface.cpp
  44. 23
      test/SolidityEndToEndTest.cpp
  45. 37
      test/SolidityNameAndTypeResolution.cpp
  46. 80
      test/SolidityOptimizer.cpp
  47. 32
      test/TestHelper.cpp
  48. 1
      test/TestHelper.h
  49. 18
      test/blockchain.cpp
  50. 45
      test/net.cpp
  51. 47
      test/peer.cpp
  52. 2
      test/stQuadraticComplexityTestFiller.json
  53. 78
      test/stTransactionTestFiller.json
  54. 1
      test/transaction.cpp
  55. 3
      test/tt10mbDataFieldFiller.json
  56. 2
      test/ttTransactionTestFiller.json
  57. 4
      test/vm.cpp

134
CMakeLists.txt

@ -8,30 +8,26 @@ project(ethereum)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
###################################################################################################### ######################################################################################################
# user defined, defaults # user defined, defaults
# Normally, set(...CACHE...) creates cache variables, but does not modify them. # Normally, set(...CACHE...) creates cache variables, but does not modify them.
function(createDefaultCacheConfig) option(VMTRACE "VM tracing and run-time checks (useful for cross-implementation VM debugging)" OFF)
set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)") option(PARANOID "Additional run-time checks" OFF)
set(PARANOID OFF CACHE BOOL "Additional run-time checks") option(JSONRPC "Build with jsonprc. default on" ON)
set(JSONRPC ON CACHE BOOL "Build with jsonprc. default on") option(FATDB "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents." OFF)
set(FATDB OFF CACHE BOOL "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents.") option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF)
set(USENPM OFF CACHE BOOL "Use npm to recompile ethereum.js if it was changed") option(PROFILING "Build in support for profiling" OFF)
set(PROFILING OFF CACHE BOOL "Build in support for profiling")
set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).") set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).")
set(SOLIDITY ON CACHE BOOL "Build the Solidity language components") option(SOLIDITY "Build the Solidity language components" ON)
set(SERPENT ON CACHE BOOL "Build the Serpent language components") option(SERPENT "Build the Serpent language components" ON)
set(TOOLS ON CACHE BOOL "Build the tools components") option(TOOLS "Build the tools components" ON)
set(NCURSES ON CACHE BOOL "Build the NCurses components") option(NCURSES "Build the NCurses components" ON)
set(GUI ON CACHE BOOL "Build GUI components (AlethZero, Mix)") option(GUI "Build GUI components (AlethZero, Mix)" ON)
set(TESTS ON CACHE BOOL "Build the tests.") option(TESTS "Build the tests." ON)
set(EVMJIT OFF CACHE BOOL "Build just-in-time compiler for EVM code (requires LLVM)") option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
set(ETHASHCL OFF CACHE BOOL "Build in support for GPU mining via OpenCL") option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
endfunction()
# propagates CMake configuration options to the compiler # propagates CMake configuration options to the compiler
function(configureProject) function(configureProject)
@ -143,96 +139,56 @@ if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
endif () endif ()
endif () endif ()
createDefaultCacheConfig()
# Force chromium. # Force chromium.
set (ETH_HAVE_WEBENGINE 1) set (ETH_HAVE_WEBENGINE 1)
# Normalise build options
# TODO: Abstract into something sensible and move into a function.
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(DECENT_PLATFORM OFF)
else ()
set(DECENT_PLATFORM ON)
endif ()
# Backwards compatibility # Backwards compatibility
if (HEADLESS) if (HEADLESS)
message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0") message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0")
set(BUNDLE "minimal") set(BUNDLE "minimal")
endif () endif ()
if (PARANOID) # TODO: Abstract into something sensible and move into a function.
set(PARANOID ON) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
else () set(DECENT_PLATFORM OFF)
set(PARANOID OFF)
endif ()
if (VMTRACE)
set(VMTRACE ON)
else ()
set(VMTRACE OFF)
endif ()
if (EVMJIT)
set(EVMJIT ON)
else ()
set(EVMJIT OFF)
endif()
if (FATDB)
set(FATDB ON)
else ()
set(FATDB OFF)
endif()
if (JSONRPC)
set(JSONRPC ON)
else () else ()
set(JSONRPC OFF) set(DECENT_PLATFORM ON)
endif () endif ()
if (USENPM)
set(USENPM ON) macro(eth_format_option O)
if (${${O}})
set(${O} ON)
else() else()
set(USENPM OFF) set(${O} OFF)
endif() endif()
if (PROFILING) endmacro()
set(PROFILING ON)
macro(eth_format_option_on_decent_platform O)
if (${${O}})
set(${O} ${DECENT_PLATFORM})
else() else()
set(PROFILING OFF) set(${O} OFF)
endif() endif()
endmacro()
# Normalise build options
eth_format_option(PARANOID)
eth_format_option(VMTRACE)
eth_format_option(EVMJIT)
eth_format_option(FATDB)
eth_format_option(JSONRPC)
eth_format_option(USENPM)
eth_format_option(PROFILING)
eth_format_option(SOLIDITY)
eth_format_option(GUI)
eth_format_option(TESTS)
eth_format_option(TOOLS)
eth_format_option(ETHASHCL)
eth_format_option_on_decent_platform(SERPENT)
eth_format_option_on_decent_platform(NCURSES)
if (SOLIDITY)
set(SOLIDITY ON)
else ()
set(SOLIDITY OFF)
endif()
if (SERPENT)
set(SERPENT ${DECENT_PLATFORM})
else ()
set(SERPENT OFF)
endif()
if (GUI) if (GUI)
set(GUI ON)
set(JSONRPC ON) set(JSONRPC ON)
else ()
set(GUI OFF)
endif ()
if (TESTS)
set(TESTS ON)
else ()
set(TESTS OFF)
endif ()
if (TOOLS)
set(TOOLS ON)
else ()
set(TOOLS OFF)
endif ()
if (ETHASHCL)
set(ETHASHCL ON)
else ()
set(ETHASHCL OFF)
endif()
if (NCURSES)
set(NCURSES ${DECENT_PLATFORM})
else ()
set(NCURSES OFF)
endif() endif()
if (BUNDLE STREQUAL "minimal") if (BUNDLE STREQUAL "minimal")

2
alethzero/MainWin.cpp

@ -1038,7 +1038,7 @@ void Main::refreshNetwork()
for (p2p::Peer const& i: ns) for (p2p::Peer const& i: ns)
ui->nodes->insertItem(sessions.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") ui->nodes->insertItem(sessions.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8")
.arg(QString::fromStdString(i.id.abridged())) .arg(QString::fromStdString(i.id.abridged()))
.arg(QString::fromStdString(i.peerEndpoint().address().to_string())) .arg(QString::fromStdString(i.endpoint.address.to_string()))
.arg(i.id == web3()->id() ? "self" : sessions.count(i.id) ? sessions[i.id] : "disconnected") .arg(i.id == web3()->id() ? "self" : sessions.count(i.id) ? sessions[i.id] : "disconnected")
.arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect())) + " | " + QString::number(i.failedAttempts()) + "x" : "") .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect())) + " | " + QString::number(i.failedAttempts()) + "x" : "")
.arg(i.rating()) .arg(i.rating())

2
eth/CMakeLists.txt

@ -25,8 +25,10 @@ if (JSONRPC)
target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS) eth_copy_dlls(${EXECUTABLE} CURL_DLLS)
endif() endif()
endif()
target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} ethash)

11
extdep/getstuff.bat

@ -23,10 +23,15 @@ set eth_version=%2
cd download cd download
if not exist %eth_name%-%eth_version%.tar.gz curl -k -o %eth_name%-%eth_version%.tar.gz %eth_server%/%eth_name%-%eth_version%.tar.gz if not exist %eth_name%-%eth_version%.tar.gz (
if not exist %eth_name%-%eth_version% tar -zxvf %eth_name%-%eth_version%.tar.gz bitsadmin /cancel %eth_name%-%eth_version%.tar.gz
bitsadmin /create %eth_name%-%eth_version%.tar.gz
bitsadmin /transfer %eth_name%-%eth_version%.tar.gz /download /priority normal %eth_server%/%eth_name%-%eth_version%.tar.gz %cd%\%eth_name%-%eth_version%.tar.gz
bitsadmin /cancel %eth_name%-%eth_version%.tar.gz
)
if not exist %eth_name%-%eth_version% cmake -E tar -zxvf %eth_name%-%eth_version%.tar.gz
cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows
cd ..\download cd ..
goto :EOF goto :EOF

207
libevmcore/Assembly.cpp

@ -23,7 +23,8 @@
#include <fstream> #include <fstream>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libevmcore/CommonSubexpressionEliminator.h> #include <libevmcore/CommonSubexpressionEliminator.h>
#include <libevmcore/ControlFlowGraph.h>
#include <json/json.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
@ -64,6 +65,13 @@ void Assembly::append(Assembly const& _a, int _deposit)
} }
} }
string Assembly::out() const
{
stringstream ret;
stream(ret);
return ret.str();
}
unsigned Assembly::bytesRequired() const unsigned Assembly::bytesRequired() const
{ {
for (unsigned br = 1;; ++br) for (unsigned br = 1;; ++br)
@ -100,7 +108,7 @@ string Assembly::getLocationFromSources(StringMap const& _sourceCodes, SourceLoc
return move(cut); return move(cut);
} }
ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
{ {
_out << _prefix << ".code:" << endl; _out << _prefix << ".code:" << endl;
for (AssemblyItem const& i: m_items) for (AssemblyItem const& i: m_items)
@ -156,6 +164,115 @@ ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const&
return _out; return _out;
} }
Json::Value Assembly::createJsonValue(string _name, int _begin, int _end, string _value, string _jumpType) const
{
Json::Value value;
value["name"] = _name;
value["begin"] = _begin;
value["end"] = _end;
if (!_value.empty())
value["value"] = _value;
if (!_jumpType.empty())
value["jumpType"] = _jumpType;
return value;
}
string toStringInHex(u256 _value)
{
std::stringstream hexStr;
hexStr << hex << _value;
return hexStr.str();
}
Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes) const
{
Json::Value root;
Json::Value collection(Json::arrayValue);
for (AssemblyItem const& i: m_items)
{
switch (i.type())
{
case Operation:
collection.append(
createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString()));
break;
case Push:
collection.append(
createJsonValue("PUSH", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()), i.getJumpTypeAsString()));
break;
case PushString:
collection.append(
createJsonValue("PUSH tag", i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data())));
break;
case PushTag:
collection.append(
createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, toStringInHex(i.data())));
break;
case PushSub:
collection.append(
createJsonValue("PUSH [$]", i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data()))));
break;
case PushSubSize:
collection.append(
createJsonValue("PUSH #[$]", i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data()))));
break;
case PushProgramSize:
collection.append(
createJsonValue("PUSHSIZE", i.getLocation().start, i.getLocation().end));
break;
case Tag:
{
collection.append(
createJsonValue("tag", i.getLocation().start, i.getLocation().end, string(i.data())));
collection.append(
createJsonValue("JUMDEST", i.getLocation().start, i.getLocation().end));
}
break;
case PushData:
{
Json::Value pushData;
pushData["name"] = "PUSH hex";
collection.append(createJsonValue("PUSH hex", i.getLocation().start, i.getLocation().end, toStringInHex(i.data())));
}
break;
default:
BOOST_THROW_EXCEPTION(InvalidOpcode());
}
}
root[".code"] = collection;
if (!m_data.empty() || !m_subs.empty())
{
Json::Value data;
for (auto const& i: m_data)
if (u256(i.first) >= m_subs.size())
data[toStringInHex((u256)i.first)] = toHex(i.second);
for (size_t i = 0; i < m_subs.size(); ++i)
{
std::stringstream hexStr;
hexStr << hex << i;
data[hexStr.str()] = m_subs[i].stream(_out, "", _sourceCodes, true);
}
root[".data"] = data;
_out << root;
}
return root;
}
Json::Value Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const
{
if (_inJsonFormat)
return streamAsmJson(_out, _sourceCodes);
else
{
streamAsm(_out, _prefix, _sourceCodes);
return Json::Value();
}
}
AssemblyItem const& Assembly::append(AssemblyItem const& _i) AssemblyItem const& Assembly::append(AssemblyItem const& _i)
{ {
m_deposit += _i.deposit(); m_deposit += _i.deposit();
@ -197,6 +314,18 @@ Assembly& Assembly::optimise(bool _enable)
copt << *this; copt << *this;
count = 0; count = 0;
copt << "Performing control flow analysis...";
{
ControlFlowGraph cfg(m_items);
AssemblyItems optItems = cfg.optimisedItems();
if (optItems.size() < m_items.size())
{
copt << "Old size: " << m_items.size() << ", new size: " << optItems.size();
m_items = move(optItems);
count++;
}
}
copt << "Performing common subexpression elimination..."; copt << "Performing common subexpression elimination...";
for (auto iter = m_items.begin(); iter != m_items.end();) for (auto iter = m_items.begin(); iter != m_items.end();)
{ {
@ -225,80 +354,6 @@ Assembly& Assembly::optimise(bool _enable)
iter = m_items.erase(orig, iter); iter = m_items.erase(orig, iter);
} }
} }
for (unsigned i = 0; i < m_items.size(); ++i)
{
for (auto const& r: rules)
{
auto vr = AssemblyItemsConstRef(&m_items).cropped(i, r.first.size());
if (matches(vr, &r.first))
{
auto rw = r.second(vr);
if (rw.size() < vr.size())
{
copt << "Rule " << vr << " matches " << AssemblyItemsConstRef(&r.first) << " becomes...";
copt << AssemblyItemsConstRef(&rw) << "\n";
if (rw.size() > vr.size())
{
// create hole in the vector
unsigned sizeIncrease = rw.size() - vr.size();
m_items.resize(m_items.size() + sizeIncrease, AssemblyItem(UndefinedItem));
move_backward(m_items.begin() + i, m_items.end() - sizeIncrease, m_items.end());
}
else
m_items.erase(m_items.begin() + i + rw.size(), m_items.begin() + i + vr.size());
copy(rw.begin(), rw.end(), m_items.begin() + i);
count++;
copt << "Now:" << m_items;
}
}
}
if (m_items[i].type() == Operation && m_items[i].instruction() == Instruction::JUMP)
{
bool o = false;
while (m_items.size() > i + 1 && m_items[i + 1].type() != Tag)
{
m_items.erase(m_items.begin() + i + 1);
o = true;
}
if (o)
{
copt << "Jump with no tag. Now:\n" << m_items;
++count;
}
}
}
map<u256, unsigned> tags;
for (unsigned i = 0; i < m_items.size(); ++i)
if (m_items[i].type() == Tag)
tags.insert(make_pair(m_items[i].data(), i));
for (auto const& i: m_items)
if (i.type() == PushTag)
tags.erase(i.data());
if (!tags.empty())
{
auto t = *tags.begin();
unsigned i = t.second;
if (i && m_items[i - 1].type() == Operation && m_items[i - 1].instruction() == Instruction::JUMP)
while (i < m_items.size() && (m_items[i].type() != Tag || tags.count(m_items[i].data())))
{
if (m_items[i].type() == Tag && tags.count(m_items[i].data()))
tags.erase(m_items[i].data());
m_items.erase(m_items.begin() + i);
}
else
{
m_items.erase(m_items.begin() + i);
tags.erase(t.first);
}
copt << "Unused tag. Now:\n" << m_items;
++count;
}
} }
copt << total << " optimisations done."; copt << total << " optimisations done.";

20
libevmcore/Assembly.h

@ -29,7 +29,12 @@
#include <libevmcore/Instruction.h> #include <libevmcore/Instruction.h>
#include <libevmcore/AssemblyItem.h> #include <libevmcore/AssemblyItem.h>
#include "Exceptions.h" #include "Exceptions.h"
#include <json/json.h>
namespace Json
{
class Value;
}
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -76,7 +81,7 @@ public:
void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); } void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); }
void injectStart(AssemblyItem const& _i); void injectStart(AssemblyItem const& _i);
std::string out() const { std::stringstream ret; stream(ret); return ret.str(); } std::string out() const;
int deposit() const { return m_deposit; } int deposit() const { return m_deposit; }
void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
@ -86,13 +91,24 @@ public:
bytes assemble() const; bytes assemble() const;
Assembly& optimise(bool _enable); Assembly& optimise(bool _enable);
std::ostream& stream(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap()) const; Json::Value stream(
std::ostream& _out,
std::string const& _prefix = "",
const StringMap &_sourceCodes = StringMap(),
bool _inJsonFormat = false
) const;
protected: protected:
std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const;
void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
unsigned bytesRequired() const; unsigned bytesRequired() const;
private:
Json::Value streamAsmJson(std::ostream& _out, const StringMap &_sourceCodes) const;
std::ostream& streamAsm(std::ostream& _out, std::string const& _prefix, StringMap const& _sourceCodes) const;
Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const;
protected:
unsigned m_usedTags = 0; unsigned m_usedTags = 0;
AssemblyItems m_items; AssemblyItems m_items;
mutable std::map<h256, bytes> m_data; mutable std::map<h256, bytes> m_data;

1
libevmcore/CMakeLists.txt

@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})

260
libevmcore/ControlFlowGraph.cpp

@ -0,0 +1,260 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ControlFlowGraph.cpp
* @author Christian <c@ethdev.com>
* @date 2015
* Control flow analysis for the optimizer.
*/
#include <libevmcore/ControlFlowGraph.h>
#include <map>
#include <libevmcore/Exceptions.h>
#include <libevmcore/AssemblyItem.h>
#include <libevmcore/SemanticInformation.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
BlockId::BlockId(u256 const& _id): m_id(_id)
{
assertThrow( _id < initial().m_id, OptimizerException, "Tag number too large.");
}
AssemblyItems ControlFlowGraph::optimisedItems()
{
if (m_items.empty())
return m_items;
findLargestTag();
splitBlocks();
resolveNextLinks();
removeUnusedBlocks();
setPrevLinks();
return rebuildCode();
}
void ControlFlowGraph::findLargestTag()
{
m_lastUsedId = 0;
for (auto const& item: m_items)
if (item.type() == Tag || item.type() == PushTag)
{
// Assert that it can be converted.
BlockId(item.data());
m_lastUsedId = max(unsigned(item.data()), m_lastUsedId);
}
}
void ControlFlowGraph::splitBlocks()
{
m_blocks.clear();
BlockId id = BlockId::initial();
m_blocks[id].begin = 0;
for (size_t index = 0; index < m_items.size(); ++index)
{
AssemblyItem const& item = m_items.at(index);
if (item.type() == Tag)
{
if (id)
m_blocks[id].end = index;
id = BlockId::invalid();
}
if (!id)
{
id = item.type() == Tag ? BlockId(item.data()) : generateNewId();
m_blocks[id].begin = index;
}
if (item.type() == PushTag)
m_blocks[id].pushedTags.push_back(BlockId(item.data()));
if (SemanticInformation::altersControlFlow(item))
{
m_blocks[id].end = index + 1;
if (item == Instruction::JUMP)
m_blocks[id].endType = BasicBlock::EndType::JUMP;
else if (item == Instruction::JUMPI)
m_blocks[id].endType = BasicBlock::EndType::JUMPI;
else
m_blocks[id].endType = BasicBlock::EndType::STOP;
id = BlockId::invalid();
}
}
if (id)
{
m_blocks[id].end = m_items.size();
if (m_blocks[id].endType == BasicBlock::EndType::HANDOVER)
m_blocks[id].endType = BasicBlock::EndType::STOP;
}
}
void ControlFlowGraph::resolveNextLinks()
{
map<unsigned, BlockId> blockByBeginPos;
for (auto const& idAndBlock: m_blocks)
if (idAndBlock.second.begin != idAndBlock.second.end)
blockByBeginPos[idAndBlock.second.begin] = idAndBlock.first;
for (auto& idAndBlock: m_blocks)
{
BasicBlock& block = idAndBlock.second;
switch (block.endType)
{
case BasicBlock::EndType::JUMPI:
case BasicBlock::EndType::HANDOVER:
assertThrow(
blockByBeginPos.count(block.end),
OptimizerException,
"Successor block not found."
);
block.next = blockByBeginPos.at(block.end);
break;
default:
break;
}
}
}
void ControlFlowGraph::removeUnusedBlocks()
{
vector<BlockId> blocksToProcess{BlockId::initial()};
set<BlockId> neededBlocks{BlockId::initial()};
while (!blocksToProcess.empty())
{
BasicBlock const& block = m_blocks.at(blocksToProcess.back());
blocksToProcess.pop_back();
for (BlockId tag: block.pushedTags)
if (!neededBlocks.count(tag))
{
neededBlocks.insert(tag);
blocksToProcess.push_back(tag);
}
if (block.next && !neededBlocks.count(block.next))
{
neededBlocks.insert(block.next);
blocksToProcess.push_back(block.next);
}
}
for (auto it = m_blocks.begin(); it != m_blocks.end();)
if (neededBlocks.count(it->first))
++it;
else
m_blocks.erase(it++);
}
void ControlFlowGraph::setPrevLinks()
{
for (auto& idAndBlock: m_blocks)
{
BasicBlock& block = idAndBlock.second;
switch (block.endType)
{
case BasicBlock::EndType::JUMPI:
case BasicBlock::EndType::HANDOVER:
assertThrow(
!m_blocks.at(block.next).prev,
OptimizerException,
"Successor already has predecessor."
);
m_blocks[block.next].prev = idAndBlock.first;
break;
default:
break;
}
}
// If block ends with jump to not yet linked block, link them removing the jump
for (auto& idAndBlock: m_blocks)
{
BlockId blockId = idAndBlock.first;
BasicBlock& block = idAndBlock.second;
if (block.endType != BasicBlock::EndType::JUMP || block.end - block.begin < 2)
continue;
AssemblyItem const& push = m_items.at(block.end - 2);
if (push.type() != PushTag)
continue;
BlockId nextId(push.data());
if (m_blocks.at(nextId).prev)
continue;
bool hasLoop = false;
for (BlockId id = nextId; id && !hasLoop; id = m_blocks.at(id).next)
hasLoop = (id == blockId);
if (hasLoop)
continue;
m_blocks[nextId].prev = blockId;
block.next = nextId;
block.end -= 2;
assertThrow(
!block.pushedTags.empty() && block.pushedTags.back() == nextId,
OptimizerException,
"Last pushed tag not at end of pushed list."
);
block.pushedTags.pop_back();
block.endType = BasicBlock::EndType::HANDOVER;
}
}
AssemblyItems ControlFlowGraph::rebuildCode()
{
map<BlockId, unsigned> pushes;
for (auto& idAndBlock: m_blocks)
for (BlockId ref: idAndBlock.second.pushedTags)
pushes[ref]++;
set<BlockId> blocksToAdd;
for (auto it: m_blocks)
blocksToAdd.insert(it.first);
set<BlockId> blocksAdded;
AssemblyItems code;
for (
BlockId blockId = BlockId::initial();
blockId;
blockId = blocksToAdd.empty() ? BlockId::invalid() : *blocksToAdd.begin()
)
{
bool previousHandedOver = (blockId == BlockId::initial());
while (m_blocks.at(blockId).prev)
blockId = m_blocks.at(blockId).prev;
for (; blockId; blockId = m_blocks.at(blockId).next)
{
BasicBlock const& block = m_blocks.at(blockId);
blocksToAdd.erase(blockId);
blocksAdded.insert(blockId);
auto begin = m_items.begin() + block.begin;
auto end = m_items.begin() + block.end;
if (begin == end)
continue;
// If block starts with unused tag, skip it.
if (previousHandedOver && !pushes[blockId] && begin->type() == Tag)
++begin;
previousHandedOver = (block.endType == BasicBlock::EndType::HANDOVER);
copy(begin, end, back_inserter(code));
}
}
return code;
}
BlockId ControlFlowGraph::generateNewId()
{
BlockId id = BlockId(++m_lastUsedId);
assertThrow(id < BlockId::initial(), OptimizerException, "Out of block IDs.");
return id;
}

108
libevmcore/ControlFlowGraph.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 <http://www.gnu.org/licenses/>.
*/
/**
* @file ControlFlowGraph.h
* @author Christian <c@ethdev.com>
* @date 2015
* Control flow analysis for the optimizer.
*/
#pragma once
#include <vector>
#include <libdevcore/Common.h>
#include <libdevcore/Assertions.h>
namespace dev
{
namespace eth
{
class AssemblyItem;
using AssemblyItems = std::vector<AssemblyItem>;
/**
* Identifier for a block, coincides with the tag number of an AssemblyItem but adds a special
* ID for the inital block.
*/
class BlockId
{
public:
BlockId() { *this = invalid(); }
explicit BlockId(unsigned _id): m_id(_id) {}
explicit BlockId(u256 const& _id);
static BlockId initial() { return BlockId(-2); }
static BlockId invalid() { return BlockId(-1); }
bool operator==(BlockId const& _other) const { return m_id == _other.m_id; }
bool operator!=(BlockId const& _other) const { return m_id != _other.m_id; }
bool operator<(BlockId const& _other) const { return m_id < _other.m_id; }
explicit operator bool() const { return *this != invalid(); }
private:
unsigned m_id;
};
/**
* Control flow block inside which instruction counter is always incremented by one
* (except for possibly the last instruction).
*/
struct BasicBlock
{
/// Start index into assembly item list.
unsigned begin = 0;
/// End index (excluded) inte assembly item list.
unsigned end = 0;
/// Tags pushed inside this block, with multiplicity.
std::vector<BlockId> pushedTags;
/// ID of the block that always follows this one (either JUMP or flow into new block),
/// or BlockId::invalid() otherwise
BlockId next = BlockId::invalid();
/// ID of the block that has to precede this one.
BlockId prev = BlockId::invalid();
enum class EndType { JUMP, JUMPI, STOP, HANDOVER };
EndType endType = EndType::HANDOVER;
};
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();
private:
void findLargestTag();
void splitBlocks();
void resolveNextLinks();
void removeUnusedBlocks();
void setPrevLinks();
AssemblyItems rebuildCode();
BlockId generateNewId();
unsigned m_lastUsedId = 0;
AssemblyItems const& m_items;
std::map<BlockId, BasicBlock> m_blocks;
};
}
}

19
libevmcore/SemanticInformation.cpp

@ -103,3 +103,22 @@ bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
{ {
return _item == AssemblyItem(Instruction::JUMP) || _item == AssemblyItem(Instruction::JUMPI); return _item == AssemblyItem(Instruction::JUMP) || _item == AssemblyItem(Instruction::JUMPI);
} }
bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
{
if (_item.type() != Operation)
return false;
switch (_item.instruction())
{
// note that CALL, CALLCODE and CREATE do not really alter the control flow, because we
// continue on the next instruction (unless an exception happens which can always happen)
case Instruction::JUMP:
case Instruction::JUMPI:
case Instruction::RETURN:
case Instruction::SUICIDE:
case Instruction::STOP:
return true;
default:
return false;
}
}

1
libevmcore/SemanticInformation.h

@ -44,6 +44,7 @@ struct SemanticInformation
static bool isDupInstruction(AssemblyItem const& _item); static bool isDupInstruction(AssemblyItem const& _item);
static bool isSwapInstruction(AssemblyItem const& _item); static bool isSwapInstruction(AssemblyItem const& _item);
static bool isJumpInstruction(AssemblyItem const& _item); static bool isJumpInstruction(AssemblyItem const& _item);
static bool altersControlFlow(AssemblyItem const& _item);
}; };
} }

1
liblll/CMakeLists.txt

@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})

16
libp2p/Common.cpp

@ -27,6 +27,11 @@ using namespace dev::p2p;
const unsigned dev::p2p::c_protocolVersion = 3; const unsigned dev::p2p::c_protocolVersion = 3;
const unsigned dev::p2p::c_defaultIPPort = 30303; const unsigned dev::p2p::c_defaultIPPort = 30303;
const dev::p2p::NodeIPEndpoint dev::p2p::UnspecifiedNodeIPEndpoint = NodeIPEndpoint(bi::address(), 0, 0);
const dev::p2p::Node dev::p2p::UnspecifiedNode = dev::p2p::Node(NodeId(), UnspecifiedNodeIPEndpoint);
bool dev::p2p::NodeIPEndpoint::test_allowLocal = false;
bool p2p::isPublicAddress(std::string const& _addressToCheck) bool p2p::isPublicAddress(std::string const& _addressToCheck)
{ {
return _addressToCheck.empty() ? false : isPublicAddress(bi::address::from_string(_addressToCheck)); return _addressToCheck.empty() ? false : isPublicAddress(bi::address::from_string(_addressToCheck));
@ -111,8 +116,13 @@ std::string p2p::reasonOf(DisconnectReason _r)
} }
} }
void Node::cullEndpoint() namespace dev {
std::ostream& operator<<(std::ostream& _out, dev::p2p::NodeIPEndpoint const& _ep)
{ {
if (!isPublicAddress(endpoint.tcp.address()) && isPublicAddress(endpoint.udp.address())) _out << _ep.address << _ep.udpPort << _ep.tcpPort;
endpoint.tcp.address(endpoint.udp.address()); return _out;
} }
}

33
libp2p/Common.h

@ -52,6 +52,11 @@ namespace p2p
extern const unsigned c_protocolVersion; extern const unsigned c_protocolVersion;
extern const unsigned c_defaultIPPort; extern const unsigned c_defaultIPPort;
struct NodeIPEndpoint;
struct Node;
extern const NodeIPEndpoint UnspecifiedNodeIPEndpoint;
extern const Node UnspecifiedNode;
using NodeId = h512; using NodeId = h512;
bool isPrivateAddress(bi::address const& _addressToCheck); bool isPrivateAddress(bi::address const& _addressToCheck);
@ -156,29 +161,30 @@ using PeerSessionInfos = std::vector<PeerSessionInfo>;
*/ */
struct NodeIPEndpoint struct NodeIPEndpoint
{ {
NodeIPEndpoint(): udp(bi::udp::endpoint()), tcp(bi::tcp::endpoint()) {} /// Setting true causes isAllowed to return true for all addresses. (Used by test fixtures)
NodeIPEndpoint(bi::udp::endpoint _udp): udp(_udp) {} static bool test_allowLocal;
NodeIPEndpoint(bi::tcp::endpoint _tcp): tcp(_tcp) {}
NodeIPEndpoint(bi::udp::endpoint _udp, bi::tcp::endpoint _tcp): udp(_udp), tcp(_tcp) {} NodeIPEndpoint(bi::address _addr, uint16_t _udp, uint16_t _tcp): address(_addr), udpPort(_udp), tcpPort(_tcp) {}
bi::address address;
uint16_t udpPort;
uint16_t tcpPort;
bi::udp::endpoint udp; operator bi::udp::endpoint() const { return std::move(bi::udp::endpoint(address, udpPort)); }
bi::tcp::endpoint tcp; operator bi::tcp::endpoint() const { return std::move(bi::tcp::endpoint(address, tcpPort)); }
operator bool() const { return !udp.address().is_unspecified() || !tcp.address().is_unspecified(); } operator bool() const { return !address.is_unspecified() && udpPort > 0 && tcpPort > 0; }
bool isAllowed() const { return NodeIPEndpoint::test_allowLocal ? !address.is_unspecified() : isPublicAddress(address); }
}; };
struct Node struct Node
{ {
Node(): endpoint(NodeIPEndpoint()) {};
Node(Public _pubk, NodeIPEndpoint _ip, bool _required = false): id(_pubk), endpoint(_ip), required(_required) {} Node(Public _pubk, NodeIPEndpoint _ip, bool _required = false): id(_pubk), endpoint(_ip), required(_required) {}
Node(Public _pubk, bi::udp::endpoint _udp, bool _required = false): Node(_pubk, NodeIPEndpoint(_udp), _required) {}
virtual NodeId const& address() const { return id; } virtual NodeId const& address() const { return id; }
virtual Public const& publicKey() const { return id; } virtual Public const& publicKey() const { return id; }
/// Adopt UDP address for TCP if TCP isn't public and UDP is. (to be removed when protocol is updated for nat)
void cullEndpoint();
NodeId id; NodeId id;
/// Endpoints by which we expect to reach node. /// Endpoints by which we expect to reach node.
@ -192,4 +198,7 @@ struct Node
}; };
} }
/// Simple stream output for a NodeIPEndpoint.
std::ostream& operator<<(std::ostream& _out, dev::p2p::NodeIPEndpoint const& _ep);
} }

147
libp2p/Host.cpp

@ -174,17 +174,25 @@ void Host::doneWorking()
void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io, bi::tcp::endpoint _endpoint) void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io, bi::tcp::endpoint _endpoint)
{ {
// session maybe ingress or egress so m_peers and node table entries may not exist
shared_ptr<Peer> p; shared_ptr<Peer> p;
if (!m_peers.count(_id)) ETH_RECURSIVE_GUARDED(x_sessions)
{ {
p.reset(new Peer()); if (m_peers.count(_id))
p->id = _id;
}
else
p = m_peers[_id]; p = m_peers[_id];
else
{
// peer doesn't exist, try to get port info from node table
if (Node n = m_nodeTable->node(_id))
p.reset(new Peer(n));
else
p.reset(new Peer(Node(_id, UnspecifiedNodeIPEndpoint)));
m_peers[_id] = p;
}
}
if (p->isOffline()) if (p->isOffline())
p->m_lastConnected = std::chrono::system_clock::now(); p->m_lastConnected = std::chrono::system_clock::now();
p->endpoint.tcp.address(_endpoint.address()); p->endpoint.address = _endpoint.address();
auto protocolVersion = _rlp[0].toInt<unsigned>(); auto protocolVersion = _rlp[0].toInt<unsigned>();
auto clientVersion = _rlp[1].toString(); auto clientVersion = _rlp[1].toString();
@ -231,46 +239,32 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
} }
clog(NetNote) << "p2p.host.peer.register" << _id.abridged(); clog(NetNote) << "p2p.host.peer.register" << _id.abridged();
StructuredLogger::p2pConnected(_id.abridged(), ps->m_peer->peerEndpoint(), ps->m_peer->m_lastConnected, clientVersion, peerCount()); StructuredLogger::p2pConnected(_id.abridged(), ps->m_peer->endpoint, ps->m_peer->m_lastConnected, clientVersion, peerCount());
} }
void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
{ {
if (_e == NodeEntryAdded) if (_e == NodeEntryAdded)
{ {
clog(NetNote) << "p2p.host.nodeTable.events.nodeEntryAdded " << _n; clog(NetNote) << "p2p.host.nodeTable.events.nodeEntryAdded " << _n;
// only add iff node is in node table
auto n = m_nodeTable->node(_n); if (Node n = m_nodeTable->node(_n))
if (n)
{ {
shared_ptr<Peer> p; shared_ptr<Peer> p;
ETH_RECURSIVE_GUARDED(x_sessions)
{ {
RecursiveGuard l(x_sessions);
if (m_peers.count(_n)) if (m_peers.count(_n))
{
p = m_peers[_n]; p = m_peers[_n];
p->endpoint = n.endpoint;
}
else else
{ {
// TODO p2p: construct peer from node p.reset(new Peer(n));
p.reset(new Peer());
p->id = _n;
p->endpoint = NodeIPEndpoint(n.endpoint.udp, n.endpoint.tcp);
p->required = n.required;
m_peers[_n] = p; m_peers[_n] = p;
clog(NetNote) << "p2p.host.peers.events.peerAdded " << _n << p->endpoint;
clog(NetNote) << "p2p.host.peers.events.peersAdded " << _n << "udp:" << p->endpoint.udp.address() << "tcp:" << p->endpoint.tcp.address();
} }
p->endpoint.tcp = n.endpoint.tcp;
} }
// TODO: Implement similar to discover. Attempt connecting to nodes
// until ideal peer count is reached; if all nodes are tried,
// repeat. Notably, this is an integrated process such that
// when onNodeTableEvent occurs we should also update +/-
// the list of nodes to be tried. Thus:
// 1) externalize connection attempts
// 2) attempt copies potentialPeer list
// 3) replace this logic w/maintenance of potentialPeers
if (peerCount() < m_idealPeerCount) if (peerCount() < m_idealPeerCount)
connect(p); connect(p);
} }
@ -278,7 +272,6 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
else if (_e == NodeEntryDropped) else if (_e == NodeEntryDropped)
{ {
clog(NetNote) << "p2p.host.nodeTable.events.NodeEntryDropped " << _n; clog(NetNote) << "p2p.host.nodeTable.events.NodeEntryDropped " << _n;
RecursiveGuard l(x_sessions); RecursiveGuard l(x_sessions);
m_peers.erase(_n); m_peers.erase(_n);
} }
@ -381,7 +374,7 @@ string Host::pocHost()
return "poc-" + strs[1] + ".ethdev.com"; return "poc-" + strs[1] + ".ethdev.com";
} }
void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpNodePort, unsigned short _tcpPeerPort) void Host::addNode(NodeId const& _node, NodeIPEndpoint const& _endpoint)
{ {
// return if network is stopped while waiting on Host::run() or nodeTable to start // return if network is stopped while waiting on Host::run() or nodeTable to start
while (!haveNetwork()) while (!haveNetwork())
@ -390,43 +383,33 @@ void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short
else else
return; return;
if (_tcpPeerPort < 30300 || _tcpPeerPort > 30305) if (_endpoint.tcpPort < 30300 || _endpoint.tcpPort > 30305)
cwarn << "Non-standard port being recorded: " << _tcpPeerPort; clog(NetConnect) << "Non-standard port being recorded: " << _endpoint.tcpPort;
if (_tcpPeerPort >= /*49152*/32768)
{
cwarn << "Private port being recorded - setting to 0";
_tcpPeerPort = 0;
}
if (m_nodeTable) if (m_nodeTable)
m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(_addr, _udpNodePort), bi::tcp::endpoint(_addr, _tcpPeerPort)))); m_nodeTable->addNode(Node(_node, _endpoint));
} }
void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr, unsigned short _tcpPort) void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint)
{ {
auto naddr = _udpAddr; Node node(_n, _endpoint, true);
auto paddr = _tcpAddr.is_unspecified() ? naddr : _tcpAddr;
auto udp = bi::udp::endpoint(naddr, _udpPort);
auto tcp = bi::tcp::endpoint(paddr, _tcpPort ? _tcpPort : _udpPort);
Node node(_n, NodeIPEndpoint(udp, tcp));
if (_n) if (_n)
{ {
// add or replace peer // create or update m_peers entry
shared_ptr<Peer> p; shared_ptr<Peer> p;
ETH_RECURSIVE_GUARDED(x_sessions)
{ {
RecursiveGuard l(x_sessions);
if (m_peers.count(_n)) if (m_peers.count(_n))
{
p = m_peers[_n]; p = m_peers[_n];
p->endpoint = node.endpoint;
p->required = true;
}
else else
{ {
p.reset(new Peer()); p.reset(new Peer(node));
p->id = _n;
p->required = true;
m_peers[_n] = p; m_peers[_n] = p;
} }
p->endpoint.udp = node.endpoint.udp;
p->endpoint.tcp = node.endpoint.tcp;
} }
connect(p); connect(p);
} }
@ -441,7 +424,7 @@ void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned s
{ {
if (!_ec && m_nodeTable) if (!_ec && m_nodeTable)
if (auto n = m_nodeTable->node(_n)) if (auto n = m_nodeTable->node(_n))
requirePeer(n.id, n.endpoint.udp.address(), n.endpoint.udp.port(), n.endpoint.tcp.address(), n.endpoint.tcp.port()); requirePeer(n.id, n.endpoint);
}); });
} }
} }
@ -482,22 +465,23 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
m_pendingPeerConns.insert(nptr); m_pendingPeerConns.insert(nptr);
} }
clog(NetConnect) << "Attempting connection to node" << _p->id.abridged() << "@" << _p->peerEndpoint() << "from" << id().abridged(); bi::tcp::endpoint ep(_p->endpoint);
clog(NetConnect) << "Attempting connection to node" << _p->id.abridged() << "@" << ep << "from" << id().abridged();
auto socket = make_shared<RLPXSocket>(new bi::tcp::socket(m_ioService)); auto socket = make_shared<RLPXSocket>(new bi::tcp::socket(m_ioService));
socket->ref().async_connect(_p->peerEndpoint(), [=](boost::system::error_code const& ec) socket->ref().async_connect(ep, [=](boost::system::error_code const& ec)
{ {
_p->m_lastAttempted = std::chrono::system_clock::now(); _p->m_lastAttempted = std::chrono::system_clock::now();
_p->m_failedAttempts++; _p->m_failedAttempts++;
if (ec) if (ec)
{ {
clog(NetConnect) << "Connection refused to node" << _p->id.abridged() << "@" << _p->peerEndpoint() << "(" << ec.message() << ")"; clog(NetConnect) << "Connection refused to node" << _p->id.abridged() << "@" << ep << "(" << ec.message() << ")";
// Manually set error (session not present) // Manually set error (session not present)
_p->m_lastDisconnect = TCPError; _p->m_lastDisconnect = TCPError;
} }
else else
{ {
clog(NetConnect) << "Connecting to" << _p->id.abridged() << "@" << _p->peerEndpoint(); clog(NetConnect) << "Connecting to" << _p->id.abridged() << "@" << ep;
auto handshake = make_shared<RLPXHandshake>(this, socket, _p->id); auto handshake = make_shared<RLPXHandshake>(this, socket, _p->id);
{ {
Guard l(x_connecting); Guard l(x_connecting);
@ -579,7 +563,7 @@ void Host::run(boost::system::error_code const&)
// is always live and to ensure reputation and fallback timers are properly // is always live and to ensure reputation and fallback timers are properly
// updated. // disconnectLatePeers(); // updated. // disconnectLatePeers();
auto openSlots = m_idealPeerCount - peerCount(); int openSlots = m_idealPeerCount - peerCount();
if (openSlots > 0) if (openSlots > 0)
{ {
list<shared_ptr<Peer>> toConnect; list<shared_ptr<Peer>> toConnect;
@ -637,7 +621,7 @@ void Host::startedWorking()
else else
clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "TCP Listen port is invalid or unavailable."; clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "TCP Listen port is invalid or unavailable.";
shared_ptr<NodeTable> nodeTable(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort())); shared_ptr<NodeTable> nodeTable(new NodeTable(m_ioService, m_alias, NodeIPEndpoint(bi::address::from_string(listenAddress()), listenPort(), listenPort())));
nodeTable->setEventHandler(new HostNodeTableHandler(*this)); nodeTable->setEventHandler(new HostNodeTableHandler(*this));
m_nodeTable = nodeTable; m_nodeTable = nodeTable;
restoreNetwork(&m_restoreNetwork); restoreNetwork(&m_restoreNetwork);
@ -696,14 +680,13 @@ bytes Host::saveNetwork() const
{ {
// Only save peers which have connected within 2 days, with properly-advertised port and public IP address // Only save peers which have connected within 2 days, with properly-advertised port and public IP address
// todo: e2e ipv6 support // todo: e2e ipv6 support
bi::tcp::endpoint endpoint(p.peerEndpoint()); if (!p.endpoint.address.is_v4())
if (!endpoint.address().is_v4())
continue; continue;
if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && endpoint.port() > 0 && endpoint.port() < /*49152*/32768 && p.id != id() && !isPrivateAddress(p.endpoint.udp.address()) && !isPrivateAddress(endpoint.address())) if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && p.endpoint.tcpPort > 0 && p.id != id() && (p.required || p.endpoint.isAllowed()))
{ {
network.appendList(10); network.appendList(10);
network << endpoint.port() << p.id << p.required network << p.endpoint.address.to_v4().to_bytes() << p.endpoint.tcpPort << p.id << p.required
<< chrono::duration_cast<chrono::seconds>(p.m_lastConnected.time_since_epoch()).count() << chrono::duration_cast<chrono::seconds>(p.m_lastConnected.time_since_epoch()).count()
<< chrono::duration_cast<chrono::seconds>(p.m_lastAttempted.time_since_epoch()).count() << chrono::duration_cast<chrono::seconds>(p.m_lastAttempted.time_since_epoch()).count()
<< p.m_failedAttempts << (unsigned)p.m_lastDisconnect << p.m_score << p.m_rating; << p.m_failedAttempts << (unsigned)p.m_lastDisconnect << p.m_score << p.m_rating;
@ -715,14 +698,14 @@ bytes Host::saveNetwork() const
{ {
auto state = m_nodeTable->snapshot(); auto state = m_nodeTable->snapshot();
state.sort(); state.sort();
for (auto const& s: state) for (auto const& entry: state)
{ {
network.appendList(3); network.appendList(3);
if (s.endpoint.tcp.address().is_v4()) if (entry.endpoint.address.is_v4())
network << s.endpoint.tcp.address().to_v4().to_bytes(); network << entry.endpoint.address.to_v4().to_bytes();
else else
network << s.endpoint.tcp.address().to_v6().to_bytes(); network << entry.endpoint.address.to_v6().to_bytes();
network << s.endpoint.tcp.port() << s.id; network << entry.endpoint.tcpPort << entry.id;
count++; count++;
} }
} }
@ -755,36 +738,28 @@ void Host::restoreNetwork(bytesConstRef _b)
for (auto i: r[2]) for (auto i: r[2])
{ {
// todo: e2e ipv6 support
// bi::tcp::endpoint(bi::address_v6(i[0].toArray<byte, 16>()), i[1].toInt<short>());
if (i[0].itemCount() != 4) if (i[0].itemCount() != 4)
continue; continue;
bi::tcp::endpoint tcp;
bi::udp::endpoint udp;
tcp = bi::tcp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>());
udp = bi::udp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>());
if (isPrivateAddress(tcp.address()) || isPrivateAddress(udp.address()))
continue;
auto id = (NodeId)i[2]; // todo: ipv6, bi::address_v6(i[0].toArray<byte, 16>()
if (i.itemCount() == 3) Node n((NodeId)i[2], NodeIPEndpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<uint16_t>(), i[1].toInt<uint16_t>()));
m_nodeTable->addNode(id, udp, tcp); if (i.itemCount() == 3 && n.endpoint.isAllowed())
m_nodeTable->addNode(n);
else if (i.itemCount() == 10) else if (i.itemCount() == 10)
{ {
shared_ptr<Peer> p = make_shared<Peer>(); n.required = i[3].toInt<bool>();
p->id = id; if (!n.endpoint.isAllowed() && !n.required)
p->required = i[3].toInt<bool>(); continue;
shared_ptr<Peer> p = make_shared<Peer>(n);
p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt<unsigned>())); p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt<unsigned>()));
p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>())); p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>()));
p->m_failedAttempts = i[6].toInt<unsigned>(); p->m_failedAttempts = i[6].toInt<unsigned>();
p->m_lastDisconnect = (DisconnectReason)i[7].toInt<unsigned>(); p->m_lastDisconnect = (DisconnectReason)i[7].toInt<unsigned>();
p->m_score = (int)i[8].toInt<unsigned>(); p->m_score = (int)i[8].toInt<unsigned>();
p->m_rating = (int)i[9].toInt<unsigned>(); p->m_rating = (int)i[9].toInt<unsigned>();
p->endpoint.tcp = tcp;
p->endpoint.udp = udp;
m_peers[p->id] = p; m_peers[p->id] = p;
if (p->required) if (p->required)
requirePeer(p->id, p->endpoint.udp.address(), p->endpoint.udp.port()); requirePeer(p->id, n.endpoint);
else else
m_nodeTable->addNode(*p.get()); m_nodeTable->addNode(*p.get());
} }

7
libp2p/Host.h

@ -103,10 +103,13 @@ public:
template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } } template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } }
/// Add node as a peer candidate. Node is added if discovery ping is successful and table has capacity. /// Add node as a peer candidate. Node is added if discovery ping is successful and table has capacity.
void addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort); void addNode(NodeId const& _node, NodeIPEndpoint const& _endpoint);
/// Create Peer and attempt keeping peer connected. /// Create Peer and attempt keeping peer connected.
void requirePeer(NodeId const& _node, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr = bi::address(), unsigned short _tcpPort = 0); void requirePeer(NodeId const& _node, NodeIPEndpoint const& _endpoint);
/// Create Peer and attempt keeping peer connected.
void requirePeer(NodeId const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort) { requirePeer(_node, NodeIPEndpoint(_addr, _udpPort, _tcpPort)); }
/// Note peer as no longer being required. /// Note peer as no longer being required.
void relinquishPeer(NodeId const& _node); void relinquishPeer(NodeId const& _node);

61
libp2p/NodeTable.cpp

@ -25,13 +25,12 @@ using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
NodeEntry::NodeEntry(Node _src, Public _pubk, NodeIPEndpoint _gw): Node(_pubk, _gw), distance(NodeTable::distance(_src.id,_pubk)) {} NodeEntry::NodeEntry(Node _src, Public _pubk, NodeIPEndpoint _gw): Node(_pubk, _gw), distance(NodeTable::distance(_src.id,_pubk)) {}
NodeEntry::NodeEntry(Node _src, Public _pubk, bi::udp::endpoint _udp): Node(_pubk, NodeIPEndpoint(_udp)), distance(NodeTable::distance(_src.id,_pubk)) {}
NodeTable::NodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _udpAddress, uint16_t _udp): NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint):
m_node(Node(_alias.pub(), bi::udp::endpoint(_udpAddress, _udp))), m_node(Node(_alias.pub(), _endpoint)),
m_secret(_alias.sec()), m_secret(_alias.sec()),
m_io(_io), m_io(_io),
m_socket(new NodeSocket(m_io, *this, m_node.endpoint.udp)), m_socket(new NodeSocket(m_io, *this, (bi::udp::endpoint)m_node.endpoint)),
m_socketPointer(m_socket.get()), m_socketPointer(m_socket.get()),
m_bucketRefreshTimer(m_io), m_bucketRefreshTimer(m_io),
m_evictionCheckTimer(m_io) m_evictionCheckTimer(m_io)
@ -62,9 +61,9 @@ void NodeTable::processEvents()
m_nodeEventHandler->processEvents(); m_nodeEventHandler->processEvents();
} }
shared_ptr<NodeEntry> NodeTable::addNode(Public const& _pubk, bi::udp::endpoint const& _udp, bi::tcp::endpoint const& _tcp) shared_ptr<NodeEntry> NodeTable::addNode(Public const& _pubk, NodeIPEndpoint const& _ep)
{ {
auto node = Node(_pubk, NodeIPEndpoint(_udp, _tcp)); auto node = Node(_pubk, _ep);
return addNode(node); return addNode(node);
} }
@ -72,7 +71,7 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
{ {
// re-enable tcp checks when NAT hosts are handled by discover // re-enable tcp checks when NAT hosts are handled by discover
// we handle when tcp endpoint is 0 below // we handle when tcp endpoint is 0 below
if (_node.endpoint.udp.address().to_string() == "0.0.0.0") if (_node.endpoint.address.to_string() == "0.0.0.0")
{ {
clog(NodeTableWarn) << "addNode Failed. Invalid UDP address 0.0.0.0 for" << _node.id.abridged(); clog(NodeTableWarn) << "addNode Failed. Invalid UDP address 0.0.0.0 for" << _node.id.abridged();
return move(shared_ptr<NodeEntry>()); return move(shared_ptr<NodeEntry>());
@ -81,12 +80,12 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
// ping address to recover nodeid if nodeid is empty // ping address to recover nodeid if nodeid is empty
if (!_node.id) if (!_node.id)
{ {
clog(NodeTableConnect) << "Sending public key discovery Ping to" << _node.endpoint.udp << "(Advertising:" << m_node.endpoint.udp << ")"; clog(NodeTableConnect) << "Sending public key discovery Ping to" << (bi::udp::endpoint)_node.endpoint << "(Advertising:" << (bi::udp::endpoint)m_node.endpoint << ")";
{ {
Guard l(x_pubkDiscoverPings); Guard l(x_pubkDiscoverPings);
m_pubkDiscoverPings[_node.endpoint.udp.address()] = std::chrono::steady_clock::now(); m_pubkDiscoverPings[_node.endpoint.address] = std::chrono::steady_clock::now();
} }
PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); PingNode p(_node.endpoint, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort);
p.sign(m_secret); p.sign(m_secret);
m_socketPointer->send(p); m_socketPointer->send(p);
return move(shared_ptr<NodeEntry>()); return move(shared_ptr<NodeEntry>());
@ -98,11 +97,10 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
return m_nodes[_node.id]; return m_nodes[_node.id];
} }
shared_ptr<NodeEntry> ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp))); shared_ptr<NodeEntry> ret(new NodeEntry(m_node, _node.id, _node.endpoint));
m_nodes[_node.id] = ret; m_nodes[_node.id] = ret;
ret->cullEndpoint(); clog(NodeTableConnect) << "addNode pending for" << _node.endpoint;
clog(NodeTableConnect) << "addNode pending for" << _node.endpoint.udp << _node.endpoint.tcp; PingNode p(_node.endpoint, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort);
PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port());
p.sign(m_secret); p.sign(m_secret);
m_socketPointer->send(p); m_socketPointer->send(p);
return ret; return ret;
@ -143,10 +141,10 @@ Node NodeTable::node(NodeId const& _id)
if (m_nodes.count(_id)) if (m_nodes.count(_id))
{ {
auto entry = m_nodes[_id]; auto entry = m_nodes[_id];
Node n(_id, NodeIPEndpoint(entry->endpoint.udp, entry->endpoint.tcp), entry->required); Node n(_id, entry->endpoint, entry->required);
return move(n); return move(n);
} }
return move(Node()); return UnspecifiedNode;
} }
shared_ptr<NodeEntry> NodeTable::nodeEntry(NodeId _id) shared_ptr<NodeEntry> NodeTable::nodeEntry(NodeId _id)
@ -176,7 +174,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr<set<shared_pt
{ {
auto r = nearest[i]; auto r = nearest[i];
tried.push_back(r); tried.push_back(r);
FindNode p(r->endpoint.udp, _node); FindNode p(r->endpoint, _node);
p.sign(m_secret); p.sign(m_secret);
m_findNodeTimeout.push_back(make_pair(r->id, chrono::steady_clock::now())); m_findNodeTimeout.push_back(make_pair(r->id, chrono::steady_clock::now()));
m_socketPointer->send(p); m_socketPointer->send(p);
@ -274,13 +272,14 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeId _target)
vector<shared_ptr<NodeEntry>> ret; vector<shared_ptr<NodeEntry>> ret;
for (auto& nodes: found) for (auto& nodes: found)
for (auto n: nodes.second) for (auto n: nodes.second)
if (n->endpoint.isAllowed())
ret.push_back(n); ret.push_back(n);
return move(ret); return move(ret);
} }
void NodeTable::ping(bi::udp::endpoint _to) const void NodeTable::ping(bi::udp::endpoint _to) const
{ {
PingNode p(_to, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); PingNode p(_to, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort);
p.sign(m_secret); p.sign(m_secret);
m_socketPointer->send(p); m_socketPointer->send(p);
} }
@ -288,7 +287,7 @@ void NodeTable::ping(bi::udp::endpoint _to) const
void NodeTable::ping(NodeEntry* _n) const void NodeTable::ping(NodeEntry* _n) const
{ {
if (_n) if (_n)
ping(_n->endpoint.udp); ping(_n->endpoint);
} }
void NodeTable::evict(shared_ptr<NodeEntry> _leastSeen, shared_ptr<NodeEntry> _new) void NodeTable::evict(shared_ptr<NodeEntry> _leastSeen, shared_ptr<NodeEntry> _new)
@ -307,16 +306,15 @@ void NodeTable::evict(shared_ptr<NodeEntry> _leastSeen, shared_ptr<NodeEntry> _n
void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint) void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint)
{ {
if (_pubk == m_node.address()) if (_pubk == m_node.address() || !NodeIPEndpoint(_endpoint.address(), _endpoint.port(), _endpoint.port()).isAllowed())
return; return;
shared_ptr<NodeEntry> node = nodeEntry(_pubk); shared_ptr<NodeEntry> node = nodeEntry(_pubk);
if (!!node && !node->pending) if (!!node && !node->pending)
{ {
clog(NodeTableConnect) << "Noting active node:" << _pubk.abridged() << _endpoint.address().to_string() << ":" << _endpoint.port(); clog(NodeTableConnect) << "Noting active node:" << _pubk.abridged() << _endpoint.address().to_string() << ":" << _endpoint.port();
node->endpoint.udp.address(_endpoint.address()); node->endpoint.address = _endpoint.address();
node->endpoint.udp.port(_endpoint.port()); node->endpoint.udpPort = _endpoint.port();
node->cullEndpoint();
shared_ptr<NodeEntry> contested; shared_ptr<NodeEntry> contested;
{ {
@ -446,7 +444,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
m_pubkDiscoverPings.erase(_from.address()); m_pubkDiscoverPings.erase(_from.address());
} }
if (!haveNode(nodeid)) if (!haveNode(nodeid))
addNode(nodeid, _from, bi::tcp::endpoint(_from.address(), _from.port())); addNode(nodeid, NodeIPEndpoint(_from.address(), _from.port(), _from.port()));
} }
else else
return; // unsolicited pong; don't note node as active return; // unsolicited pong; don't note node as active
@ -477,7 +475,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes);
for (auto n: in.nodes) for (auto n: in.nodes)
addNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port), bi::tcp::endpoint(bi::address::from_string(n.ipAddress), n.port)); addNode(n.node, NodeIPEndpoint(bi::address::from_string(n.ipAddress), n.udpPort, n.udpPort));
break; break;
} }
@ -508,7 +506,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
return; return;
} }
addNode(nodeid, _from, bi::tcp::endpoint(bi::address::from_string(in.ipAddress), in.port)); // TODO: Feedback if _from.address() != in.ipAddress
addNode(nodeid, NodeIPEndpoint(_from.address(), _from.port(), in.tcpPort));
Pong p(_from); Pong p(_from);
p.echo = sha3(rlpBytes); p.echo = sha3(rlpBytes);
@ -586,7 +585,7 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec)
void PingNode::streamRLP(RLPStream& _s) const void PingNode::streamRLP(RLPStream& _s) const
{ {
_s.appendList(4); _s.appendList(4);
_s << dev::p2p::c_protocolVersion << ipAddress << port << expiration; _s << dev::p2p::c_protocolVersion << ipAddress << tcpPort << ts;
} }
void PingNode::interpretRLP(bytesConstRef _bytes) void PingNode::interpretRLP(bytesConstRef _bytes)
@ -596,15 +595,15 @@ void PingNode::interpretRLP(bytesConstRef _bytes)
{ {
version = 2; version = 2;
ipAddress = r[0].toString(); ipAddress = r[0].toString();
port = r[1].toInt<unsigned>(RLP::Strict); tcpPort = r[1].toInt<unsigned>(RLP::Strict);
expiration = r[2].toInt<unsigned>(RLP::Strict); ts = r[2].toInt<unsigned>(RLP::Strict);
} }
else if (r.itemCountStrict() == 4) else if (r.itemCountStrict() == 4)
{ {
version = r[0].toInt<unsigned>(RLP::Strict); version = r[0].toInt<unsigned>(RLP::Strict);
ipAddress = r[1].toString(); ipAddress = r[1].toString();
port = r[2].toInt<unsigned>(RLP::Strict); tcpPort = r[2].toInt<unsigned>(RLP::Strict);
expiration = r[3].toInt<unsigned>(RLP::Strict); ts = r[3].toInt<unsigned>(RLP::Strict);
} }
else else
BOOST_THROW_EXCEPTION(InvalidRLP()); BOOST_THROW_EXCEPTION(InvalidRLP());

63
libp2p/NodeTable.h

@ -41,10 +41,7 @@ namespace p2p
struct NodeEntry: public Node struct NodeEntry: public Node
{ {
NodeEntry(Node _src, Public _pubk, NodeIPEndpoint _gw); NodeEntry(Node _src, Public _pubk, NodeIPEndpoint _gw);
NodeEntry(Node _src, Public _pubk, bi::udp::endpoint _udp);
unsigned const distance; ///< Node's distance (xor of _src as integer). unsigned const distance; ///< Node's distance (xor of _src as integer).
bool pending = true; ///< Node will be ignored until Pong is received bool pending = true; ///< Node will be ignored until Pong is received
}; };
@ -137,7 +134,7 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this<NodeTable>
public: public:
/// Constructor requiring host for I/O, credentials, and IP Address and port to listen on. /// Constructor requiring host for I/O, credentials, and IP Address and port to listen on.
NodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _udpAddress, uint16_t _udpPort = 30303); NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint);
~NodeTable(); ~NodeTable();
/// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable. /// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable.
@ -150,7 +147,7 @@ public:
void processEvents(); void processEvents();
/// Add node. Node will be pinged and empty shared_ptr is returned if NodeId is uknown. /// Add node. Node will be pinged and empty shared_ptr is returned if NodeId is uknown.
std::shared_ptr<NodeEntry> addNode(Public const& _pubk, bi::udp::endpoint const& _udp, bi::tcp::endpoint const& _tcp); std::shared_ptr<NodeEntry> addNode(Public const& _pubk, NodeIPEndpoint const& _ep);
/// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen. /// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen.
std::shared_ptr<NodeEntry> addNode(Node const& _node); std::shared_ptr<NodeEntry> addNode(Node const& _node);
@ -213,7 +210,7 @@ private:
void ping(NodeEntry* _n) const; void ping(NodeEntry* _n) const;
/// Returns center node entry which describes this node and used with dist() to calculate xor metric for node table nodes. /// Returns center node entry which describes this node and used with dist() to calculate xor metric for node table nodes.
NodeEntry center() const { return NodeEntry(m_node, m_node.publicKey(), m_node.endpoint.udp); } NodeEntry center() const { return NodeEntry(m_node, m_node.publicKey(), m_node.endpoint); }
/// Used by asynchronous operations to return NodeEntry which is active and managed by node table. /// Used by asynchronous operations to return NodeEntry which is active and managed by node table.
std::shared_ptr<NodeEntry> nodeEntry(NodeId _id); std::shared_ptr<NodeEntry> nodeEntry(NodeId _id);
@ -285,10 +282,10 @@ private:
inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable)
{ {
_out << _nodeTable.center().address() << "\t" << "0\t" << _nodeTable.center().endpoint.udp.address() << ":" << _nodeTable.center().endpoint.udp.port() << std::endl; _out << _nodeTable.center().address() << "\t" << "0\t" << _nodeTable.center().endpoint.address << ":" << _nodeTable.center().endpoint.udpPort << std::endl;
auto s = _nodeTable.snapshot(); auto s = _nodeTable.snapshot();
for (auto n: s) for (auto n: s)
_out << n.address() << "\t" << n.distance << "\t" << n.endpoint.udp.address() << ":" << n.endpoint.udp.port() << std::endl; _out << n.address() << "\t" << n.distance << "\t" << n.endpoint.address << ":" << n.endpoint.udpPort << std::endl;
return _out; return _out;
} }
@ -296,7 +293,7 @@ struct InvalidRLP: public Exception {};
/** /**
* Ping packet: Sent to check if node is alive. * Ping packet: Sent to check if node is alive.
* PingNode is cached and regenerated after expiration - t, where t is timeout. * PingNode is cached and regenerated after ts + t, where t is timeout.
* *
* Ping is used to implement evict. When a new node is seen for * Ping is used to implement evict. When a new node is seen for
* a given bucket which is full, the least-responsive node is pinged. * a given bucket which is full, the least-responsive node is pinged.
@ -310,7 +307,6 @@ struct InvalidRLP: public Exception {};
* signature: Signature of message. * signature: Signature of message.
* ipAddress: Our IP address. * ipAddress: Our IP address.
* port: Our port. * port: Our port.
* expiration: Triggers regeneration of packet. May also provide control over synchronization.
* *
* @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint) * @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint)
* *
@ -318,14 +314,15 @@ struct InvalidRLP: public Exception {};
struct PingNode: RLPXDatagram<PingNode> struct PingNode: RLPXDatagram<PingNode>
{ {
PingNode(bi::udp::endpoint _ep): RLPXDatagram<PingNode>(_ep) {} PingNode(bi::udp::endpoint _ep): RLPXDatagram<PingNode>(_ep) {}
PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram<PingNode>(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _ts = std::chrono::seconds(60)): RLPXDatagram<PingNode>(_ep), ipAddress(_src), tcpPort(_srcPort), ts(futureFromEpoch(_ts)) {}
static const uint8_t type = 1; static const uint8_t type = 1;
unsigned version = 0; unsigned version = 0;
std::string ipAddress; std::string ipAddress;
unsigned port; // uint16_t udpPort;
unsigned expiration; uint16_t tcpPort;
unsigned ts;
void streamRLP(RLPStream& _s) const override; void streamRLP(RLPStream& _s) const override;
void interpretRLP(bytesConstRef _bytes) override; void interpretRLP(bytesConstRef _bytes) override;
@ -340,20 +337,20 @@ struct PingNode: RLPXDatagram<PingNode>
*/ */
struct Pong: RLPXDatagram<Pong> struct Pong: RLPXDatagram<Pong>
{ {
Pong(bi::udp::endpoint _ep): RLPXDatagram<Pong>(_ep), expiration(futureFromEpoch(std::chrono::seconds(60))) {} Pong(bi::udp::endpoint _ep): RLPXDatagram<Pong>(_ep), ts(futureFromEpoch(std::chrono::seconds(60))) {}
static const uint8_t type = 2; static const uint8_t type = 2;
h256 echo; ///< MCD of PingNode h256 echo; ///< MCD of PingNode
unsigned expiration; unsigned ts;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << echo << expiration; } void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << echo << ts; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); echo = (h256)r[0]; expiration = r[1].toInt<unsigned>(); } void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); echo = (h256)r[0]; ts = r[1].toInt<unsigned>(); }
}; };
/** /**
* FindNode Packet: Request k-nodes, closest to the target. * FindNode Packet: Request k-nodes, closest to the target.
* FindNode is cached and regenerated after expiration - t, where t is timeout. * FindNode is cached and regenerated after ts + t, where t is timeout.
* FindNode implicitly results in finding neighbours of a given node. * FindNode implicitly results in finding neighbours of a given node.
* *
* RLP Encoded Items: 2 * RLP Encoded Items: 2
@ -361,21 +358,20 @@ struct Pong: RLPXDatagram<Pong>
* Maximum Encoded Size: 30 bytes * Maximum Encoded Size: 30 bytes
* *
* target: NodeId of node. The responding node will send back nodes closest to the target. * target: NodeId of node. The responding node will send back nodes closest to the target.
* expiration: Triggers regeneration of packet. May also provide control over synchronization.
* *
*/ */
struct FindNode: RLPXDatagram<FindNode> struct FindNode: RLPXDatagram<FindNode>
{ {
FindNode(bi::udp::endpoint _ep): RLPXDatagram<FindNode>(_ep) {} FindNode(bi::udp::endpoint _ep): RLPXDatagram<FindNode>(_ep) {}
FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram<FindNode>(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _ts = std::chrono::seconds(60)): RLPXDatagram<FindNode>(_ep), target(_target), ts(futureFromEpoch(_ts)) {}
static const uint8_t type = 3; static const uint8_t type = 3;
h512 target; h512 target;
unsigned expiration; unsigned ts;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << ts; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash<h512>(); expiration = r[1].toInt<unsigned>(); } void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash<h512>(); ts = r[1].toInt<unsigned>(); }
}; };
/** /**
@ -391,21 +387,22 @@ struct Neighbours: RLPXDatagram<Neighbours>
Node() = default; Node() = default;
Node(RLP const& _r) { interpretRLP(_r); } Node(RLP const& _r) { interpretRLP(_r); }
std::string ipAddress; std::string ipAddress;
unsigned port; uint16_t udpPort;
// uint16_t tcpPort;
NodeId node; NodeId node;
void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << udpPort << node; }
void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); port = _r[1].toInt<unsigned>(); node = h512(_r[2].toBytes()); } void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); udpPort = _r[1].toInt<uint16_t>(); node = h512(_r[2].toBytes()); }
}; };
Neighbours(bi::udp::endpoint _ep): RLPXDatagram<Neighbours>(_ep), expiration(futureFromEpoch(std::chrono::seconds(30))) {} Neighbours(bi::udp::endpoint _ep): RLPXDatagram<Neighbours>(_ep), ts(futureFromEpoch(std::chrono::seconds(30))) {}
Neighbours(bi::udp::endpoint _to, std::vector<std::shared_ptr<NodeEntry>> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram<Neighbours>(_to), expiration(futureFromEpoch(std::chrono::seconds(30))) Neighbours(bi::udp::endpoint _to, std::vector<std::shared_ptr<NodeEntry>> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram<Neighbours>(_to), ts(futureFromEpoch(std::chrono::seconds(30)))
{ {
auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size(); auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size();
for (auto i = _offset; i < limit; i++) for (auto i = _offset; i < limit; i++)
{ {
Node node; Node node;
node.ipAddress = _nearest[i]->endpoint.udp.address().to_string(); node.ipAddress = _nearest[i]->endpoint.address.to_string();
node.port = _nearest[i]->endpoint.udp.port(); node.udpPort = _nearest[i]->endpoint.udpPort;
node.node = _nearest[i]->publicKey(); node.node = _nearest[i]->publicKey();
nodes.push_back(node); nodes.push_back(node);
} }
@ -413,10 +410,10 @@ struct Neighbours: RLPXDatagram<Neighbours>
static const uint8_t type = 4; static const uint8_t type = 4;
std::vector<Node> nodes; std::vector<Node> nodes;
unsigned expiration = 1; unsigned ts = 1;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << expiration; } void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << ts; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); expiration = r[1].toInt<unsigned>(); } void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); ts = r[1].toInt<unsigned>(); }
}; };
struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; }; struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; };

2
libp2p/Peer.cpp

@ -33,7 +33,7 @@ namespace p2p
bool Peer::shouldReconnect() const bool Peer::shouldReconnect() const
{ {
return chrono::system_clock::now() > m_lastAttempted + chrono::seconds(fallbackSeconds()); return id && endpoint && chrono::system_clock::now() > m_lastAttempted + chrono::seconds(fallbackSeconds());
} }
unsigned Peer::fallbackSeconds() const unsigned Peer::fallbackSeconds() const

5
libp2p/Peer.h

@ -57,9 +57,10 @@ class Peer: public Node
friend class RLPXHandshake; friend class RLPXHandshake;
public: public:
bool isOffline() const { return !m_session.lock(); } /// Construct Peer from Node.
Peer(Node const& _node): Node(_node.id, _node.endpoint, _node.required) {}
bi::tcp::endpoint const& peerEndpoint() const { return endpoint.tcp; } bool isOffline() const { return !m_session.lock(); }
virtual bool operator<(Peer const& _p) const; virtual bool operator<(Peer const& _p) const;

12
libp2p/Session.cpp

@ -139,11 +139,11 @@ void Session::serviceNodesRequest()
auto rs = randomSelection(peers, 10); auto rs = randomSelection(peers, 10);
for (auto const& i: rs) for (auto const& i: rs)
{ {
clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.peerEndpoint(); clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.endpoint;
if (i.peerEndpoint().address().is_v4()) if (i.endpoint.address.is_v4())
s.appendList(3) << bytesConstRef(i.peerEndpoint().address().to_v4().to_bytes().data(), 4) << i.peerEndpoint().port() << i.id; s.appendList(3) << bytesConstRef(i.endpoint.address.to_v4().to_bytes().data(), 4) << i.endpoint.tcpPort << i.id;
else// if (i.second.address().is_v6()) - assumed else// if (i.second.address().is_v6()) - assumed
s.appendList(3) << bytesConstRef(i.peerEndpoint().address().to_v6().to_bytes().data(), 16) << i.peerEndpoint().port() << i.id; s.appendList(3) << bytesConstRef(i.endpoint.address.to_v6().to_bytes().data(), 16) << i.endpoint.tcpPort << i.id;
} }
sealAndSend(s); sealAndSend(s);
m_theyRequestedNodes = false; m_theyRequestedNodes = false;
@ -238,7 +238,7 @@ bool Session::interpret(PacketType _t, RLP const& _r)
// OK passed all our checks. Assume it's good. // OK passed all our checks. Assume it's good.
addRating(1000); addRating(1000);
m_server->addNode(id, ep.address(), ep.port(), ep.port()); m_server->addNode(id, NodeIPEndpoint(ep.address(), ep.port(), ep.port()));
clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")"; clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")";
CONTINUE:; CONTINUE:;
LAMEPEER:; LAMEPEER:;
@ -371,7 +371,7 @@ void Session::disconnect(DisconnectReason _reason)
clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")"; clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")";
StructuredLogger::p2pDisconnected( StructuredLogger::p2pDisconnected(
m_info.id.abridged(), m_info.id.abridged(),
m_peer->peerEndpoint(), m_peer->endpoint, // TODO: may not be 100% accurate
m_server->peerCount() m_server->peerCount()
); );
if (m_socket.is_open()) if (m_socket.is_open())

56
libsolidity/AST.cpp

@ -54,6 +54,7 @@ void ContractDefinition::checkTypeRequirements()
checkIllegalOverrides(); checkIllegalOverrides();
checkAbstractFunctions(); checkAbstractFunctions();
checkAbstractConstructors();
FunctionDefinition const* constructor = getConstructor(); FunctionDefinition const* constructor = getConstructor();
if (constructor && !constructor->getReturnParameters().empty()) if (constructor && !constructor->getReturnParameters().empty())
@ -152,6 +153,45 @@ void ContractDefinition::checkAbstractFunctions()
} }
} }
void ContractDefinition::checkAbstractConstructors()
{
set<ContractDefinition const*> argumentsNeeded;
// check that we get arguments for all base constructors that need it.
// If not mark the contract as abstract (not fully implemented)
vector<ContractDefinition const*> const& bases = getLinearizedBaseContracts();
for (ContractDefinition const* contract: bases)
if (FunctionDefinition const* constructor = contract->getConstructor())
if (contract != this && !constructor->getParameters().empty())
argumentsNeeded.insert(contract);
for (ContractDefinition const* contract: bases)
{
if (FunctionDefinition const* constructor = contract->getConstructor())
for (auto const& modifier: constructor->getModifiers())
{
auto baseContract = dynamic_cast<ContractDefinition const*>(
modifier->getName()->getReferencedDeclaration()
);
if (baseContract)
argumentsNeeded.erase(baseContract);
}
for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts())
{
auto baseContract = dynamic_cast<ContractDefinition const*>(
base->getName()->getReferencedDeclaration()
);
solAssert(baseContract, "");
if (!base->getArguments().empty())
argumentsNeeded.erase(baseContract);
}
}
if (!argumentsNeeded.empty())
setFullyImplemented(false);
}
void ContractDefinition::checkIllegalOverrides() const void ContractDefinition::checkIllegalOverrides() const
{ {
// TODO unify this at a later point. for this we need to put the constness and the access specifier // TODO unify this at a later point. for this we need to put the constness and the access specifier
@ -281,7 +321,7 @@ void InheritanceSpecifier::checkTypeRequirements()
ContractDefinition const* base = dynamic_cast<ContractDefinition const*>(m_baseName->getReferencedDeclaration()); ContractDefinition const* base = dynamic_cast<ContractDefinition const*>(m_baseName->getReferencedDeclaration());
solAssert(base, "Base contract not available."); solAssert(base, "Base contract not available.");
TypePointers parameterTypes = ContractType(*base).getConstructorType()->getParameterTypes(); TypePointers parameterTypes = ContractType(*base).getConstructorType()->getParameterTypes();
if (parameterTypes.size() != m_arguments.size()) if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call."));
for (size_t i = 0; i < m_arguments.size(); ++i) for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
@ -348,8 +388,8 @@ void FunctionDefinition::checkTypeRequirements()
} }
for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers) for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers)
modifier->checkTypeRequirements(isConstructor() ? modifier->checkTypeRequirements(isConstructor() ?
dynamic_cast<ContractDefinition const&>(*getScope()).getBaseContracts() : dynamic_cast<ContractDefinition const&>(*getScope()).getLinearizedBaseContracts() :
vector<ASTPointer<InheritanceSpecifier>>()); vector<ContractDefinition const*>());
if (m_body) if (m_body)
m_body->checkTypeRequirements(); m_body->checkTypeRequirements();
} }
@ -426,7 +466,7 @@ void ModifierDefinition::checkTypeRequirements()
m_body->checkTypeRequirements(); m_body->checkTypeRequirements();
} }
void ModifierInvocation::checkTypeRequirements(vector<ASTPointer<InheritanceSpecifier>> const& _bases) void ModifierInvocation::checkTypeRequirements(vector<ContractDefinition const*> const& _bases)
{ {
m_modifierName->checkTypeRequirements(); m_modifierName->checkTypeRequirements();
for (ASTPointer<Expression> const& argument: m_arguments) for (ASTPointer<Expression> const& argument: m_arguments)
@ -439,10 +479,10 @@ void ModifierInvocation::checkTypeRequirements(vector<ASTPointer<InheritanceSpec
parameters = &modifier->getParameters(); parameters = &modifier->getParameters();
else else
// check parameters for Base constructors // check parameters for Base constructors
for (auto const& base: _bases) for (auto const* base: _bases)
if (declaration == base->getName()->getReferencedDeclaration()) if (declaration == base)
{ {
if (auto referencedConstructor = dynamic_cast<ContractDefinition const&>(*declaration).getConstructor()) if (auto referencedConstructor = base->getConstructor())
parameters = &referencedConstructor->getParameters(); parameters = &referencedConstructor->getParameters();
else else
parameters = &emptyParameterList; parameters = &emptyParameterList;
@ -686,7 +726,7 @@ void NewExpression::checkTypeRequirements()
if (!m_contract) if (!m_contract)
BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract.")); BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract."));
if (!m_contract->isFullyImplemented()) if (!m_contract->isFullyImplemented())
BOOST_THROW_EXCEPTION(m_contract->createTypeError("Trying to create an instance of an abstract contract.")); BOOST_THROW_EXCEPTION(createTypeError("Trying to create an instance of an abstract contract."));
shared_ptr<ContractType const> contractType = make_shared<ContractType>(*m_contract); shared_ptr<ContractType const> contractType = make_shared<ContractType>(*m_contract);
TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes(); TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes();
m_type = make_shared<FunctionType>(parameterTypes, TypePointers{contractType}, m_type = make_shared<FunctionType>(parameterTypes, TypePointers{contractType},

5
libsolidity/AST.h

@ -284,6 +284,7 @@ public:
private: private:
void checkIllegalOverrides() const; void checkIllegalOverrides() const;
void checkAbstractFunctions(); void checkAbstractFunctions();
void checkAbstractConstructors();
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& getInterfaceFunctionList() const; std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& getInterfaceFunctionList() const;
@ -376,7 +377,7 @@ class EnumValue: public Declaration
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override; virtual void accept(ASTConstVisitor& _visitor) const override;
TypePointer getType(ContractDefinition const* = nullptr) const; virtual TypePointer getType(ContractDefinition const* = nullptr) const override;
}; };
/** /**
@ -566,7 +567,7 @@ public:
std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; } std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; }
/// @param _bases is the list of base contracts for base constructor calls. For modifiers an empty vector should be passed. /// @param _bases is the list of base contracts for base constructor calls. For modifiers an empty vector should be passed.
void checkTypeRequirements(std::vector<ASTPointer<InheritanceSpecifier>> const& _bases); void checkTypeRequirements(std::vector<ContractDefinition const*> const& _bases);
private: private:
ASTPointer<Identifier> m_modifierName; ASTPointer<Identifier> m_modifierName;

1
libsolidity/Compiler.cpp

@ -136,6 +136,7 @@ void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor)
FunctionType constructorType(_constructor); FunctionType constructorType(_constructor);
if (!constructorType.getParameterTypes().empty()) if (!constructorType.getParameterTypes().empty())
{ {
solAssert(m_baseArguments.count(&_constructor), "");
std::vector<ASTPointer<Expression>> const* arguments = m_baseArguments[&_constructor]; std::vector<ASTPointer<Expression>> const* arguments = m_baseArguments[&_constructor];
solAssert(arguments, ""); solAssert(arguments, "");
for (unsigned i = 0; i < arguments->size(); ++i) for (unsigned i = 0; i < arguments->size(); ++i)

5
libsolidity/Compiler.h

@ -42,9 +42,10 @@ public:
bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); }
bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);}
/// @arg _sourceCodes is the map of input files to source code strings /// @arg _sourceCodes is the map of input files to source code strings
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const /// @arg _inJsonFromat shows whether the out should be in Json format
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
{ {
m_context.streamAssembly(_stream, _sourceCodes); m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat);
} }
/// @returns Assembly items of the normal compiler context /// @returns Assembly items of the normal compiler context
eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); } eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); }

6
libsolidity/CompilerContext.h

@ -122,7 +122,11 @@ public:
eth::Assembly const& getAssembly() const { return m_asm; } eth::Assembly const& getAssembly() const { return m_asm; }
/// @arg _sourceCodes is the map of input files to source code strings /// @arg _sourceCodes is the map of input files to source code strings
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const { m_asm.stream(_stream, "", _sourceCodes); } /// @arg _inJsonFormat shows whether the out should be in Json format
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
{
m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat);
}
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }

18
libsolidity/CompilerStack.cpp

@ -157,14 +157,16 @@ bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
return getBytecode(); return getBytecode();
} }
eth::AssemblyItems const& CompilerStack::getAssemblyItems(string const& _contractName) const eth::AssemblyItems const* CompilerStack::getAssemblyItems(string const& _contractName) const
{ {
return getContract(_contractName).compiler->getAssemblyItems(); Contract const& contract = getContract(_contractName);
return contract.compiler ? &getContract(_contractName).compiler->getAssemblyItems() : nullptr;
} }
eth::AssemblyItems const& CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const eth::AssemblyItems const* CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const
{ {
return getContract(_contractName).compiler->getRuntimeAssemblyItems(); Contract const& contract = getContract(_contractName);
return contract.compiler ? &getContract(_contractName).compiler->getRuntimeAssemblyItems() : nullptr;
} }
bytes const& CompilerStack::getBytecode(string const& _contractName) const bytes const& CompilerStack::getBytecode(string const& _contractName) const
@ -182,9 +184,13 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const
return dev::sha3(getRuntimeBytecode(_contractName)); return dev::sha3(getRuntimeBytecode(_contractName));
} }
void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes) const void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const
{ {
getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes); Contract const& contract = getContract(_contractName);
if (contract.compiler)
contract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat);
else
_outStream << "Contract not fully implemented" << endl;
} }
string const& CompilerStack::getInterface(string const& _contractName) const string const& CompilerStack::getInterface(string const& _contractName) const

7
libsolidity/CompilerStack.h

@ -94,16 +94,17 @@ public:
/// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor.
bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; bytes const& getRuntimeBytecode(std::string const& _contractName = "") const;
/// @returns normal contract assembly items /// @returns normal contract assembly items
eth::AssemblyItems const& getAssemblyItems(std::string const& _contractName = "") const; eth::AssemblyItems const* getAssemblyItems(std::string const& _contractName = "") const;
/// @returns runtime contract assembly items /// @returns runtime contract assembly items
eth::AssemblyItems const& getRuntimeAssemblyItems(std::string const& _contractName = "") const; eth::AssemblyItems const* getRuntimeAssemblyItems(std::string const& _contractName = "") const;
/// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor. /// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor.
dev::h256 getContractCodeHash(std::string const& _contractName = "") const; dev::h256 getContractCodeHash(std::string const& _contractName = "") const;
/// Streams a verbose version of the assembly to @a _outStream. /// Streams a verbose version of the assembly to @a _outStream.
/// @arg _sourceCodes is the map of input files to source code strings /// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFromat shows whether the out should be in Json format
/// Prerequisite: Successful compilation. /// Prerequisite: Successful compilation.
void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const; void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const;
/// Returns a string representing the contract interface in JSON. /// Returns a string representing the contract interface in JSON.
/// Prerequisite: Successful call to parse or compile. /// Prerequisite: Successful call to parse or compile.

16
libsolidity/LValue.cpp

@ -107,6 +107,11 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
<< u256(0x100) << eth::Instruction::EXP << eth::Instruction::SWAP1 << eth::Instruction::DIV; << u256(0x100) << eth::Instruction::EXP << eth::Instruction::SWAP1 << eth::Instruction::DIV;
if (m_dataType.getCategory() == Type::Category::FixedBytes) if (m_dataType.getCategory() == Type::Category::FixedBytes)
m_context << (u256(0x1) << (256 - 8 * m_dataType.getStorageBytes())) << eth::Instruction::MUL; m_context << (u256(0x1) << (256 - 8 * m_dataType.getStorageBytes())) << eth::Instruction::MUL;
else if (
m_dataType.getCategory() == Type::Category::Integer &&
dynamic_cast<IntegerType const&>(m_dataType).isSigned()
)
m_context << u256(m_dataType.getStorageBytes() - 1) << eth::Instruction::SIGNEXTEND;
else else
m_context << ((u256(0x1) << (8 * m_dataType.getStorageBytes())) - 1) << eth::Instruction::AND; m_context << ((u256(0x1) << (8 * m_dataType.getStorageBytes())) - 1) << eth::Instruction::AND;
} }
@ -148,6 +153,17 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
m_context m_context
<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(m_dataType).getNumBytes())) << (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(m_dataType).getNumBytes()))
<< eth::Instruction::SWAP1 << eth::Instruction::DIV; << eth::Instruction::SWAP1 << eth::Instruction::DIV;
else if (
m_dataType.getCategory() == Type::Category::Integer &&
dynamic_cast<IntegerType const&>(m_dataType).isSigned()
)
// remove the higher order bits
m_context
<< (u256(1) << (8 * (32 - m_dataType.getStorageBytes())))
<< eth::Instruction::SWAP1
<< eth::Instruction::DUP2
<< eth::Instruction::MUL
<< eth::Instruction::DIV;
m_context << eth::Instruction::MUL << eth::Instruction::OR; m_context << eth::Instruction::MUL << eth::Instruction::OR;
// stack: value storage_ref updated_value // stack: value storage_ref updated_value
m_context << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; m_context << eth::Instruction::SWAP1 << eth::Instruction::SSTORE;

4
libwebthree/WebThree.cpp

@ -104,12 +104,12 @@ bytes WebThreeDirect::saveNetwork()
void WebThreeDirect::addNode(NodeId const& _node, bi::tcp::endpoint const& _host) void WebThreeDirect::addNode(NodeId const& _node, bi::tcp::endpoint const& _host)
{ {
m_net.addNode(_node, _host.address(), _host.port(), _host.port()); m_net.addNode(_node, NodeIPEndpoint(_host.address(), _host.port(), _host.port()));
} }
void WebThreeDirect::requirePeer(NodeId const& _node, bi::tcp::endpoint const& _host) void WebThreeDirect::requirePeer(NodeId const& _node, bi::tcp::endpoint const& _host)
{ {
m_net.requirePeer(_node, _host.address(), _host.port()); m_net.requirePeer(_node, NodeIPEndpoint(_host.address(), _host.port(), _host.port()));
} }

2
mix/ClientModel.cpp

@ -498,6 +498,8 @@ QVariant ClientModel::formatStorageValue(SolidityType const& _type, map<u256, u2
bytes slotBytes = toBigEndian(slotValue); bytes slotBytes = toBigEndian(slotValue);
auto start = slotBytes.end() - _type.size - offset; auto start = slotBytes.end() - _type.size - offset;
bytes val(32 - _type.size); //prepend with zeroes bytes val(32 - _type.size); //prepend with zeroes
if (_type.type == SolidityType::SignedInteger && (*start & 0x80)) //extend sign
std::fill(val.begin(), val.end(), 0xff);
val.insert(val.end(), start, start + _type.size); val.insert(val.end(), start, start + _type.size);
values.append(decoder.decode(_type, val)); values.append(decoder.decode(_type, val));
offset += _type.size; offset += _type.size;

2
mix/CodeHighlighter.cpp

@ -109,7 +109,7 @@ void CodeHighlighter::processError(dev::Exception const& _exception)
void CodeHighlighter::processComments(std::string const& _source) void CodeHighlighter::processComments(std::string const& _source)
{ {
unsigned i = 0; unsigned i = 0;
unsigned size = _source.size(); size_t size = _source.size();
if (size == 0) if (size == 0)
return; return;
while (i < size - 1) while (i < size - 1)

20
mix/CodeModel.cpp

@ -135,8 +135,8 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
CollectDeclarationsVisitor visitor(&m_functions, &m_locals); CollectDeclarationsVisitor visitor(&m_functions, &m_locals);
m_storage = collectStorage(contractDefinition); m_storage = collectStorage(contractDefinition);
contractDefinition.accept(visitor); contractDefinition.accept(visitor);
m_assemblyItems = _compiler.getRuntimeAssemblyItems(name); m_assemblyItems = *_compiler.getRuntimeAssemblyItems(name);
m_constructorAssemblyItems = _compiler.getAssemblyItems(name); m_constructorAssemblyItems = *_compiler.getAssemblyItems(name);
} }
QString CompiledContract::codeHex() const QString CompiledContract::codeHex() const
@ -299,12 +299,18 @@ void CodeModel::runCompilationJob(int _jobId)
{ {
std::ostringstream error; std::ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs);
SourceLocation const* location = boost::get_error_info<solidity::errinfo_sourceLocation>(_exception);
QString message = QString::fromStdString(error.str()); QString message = QString::fromStdString(error.str());
CompiledContract* contract = nullptr; QString sourceName;
if (location && location->sourceName.get() && (contract = contractByDocumentId(QString::fromStdString(*location->sourceName)))) if (SourceLocation const* location = boost::get_error_info<solidity::errinfo_sourceLocation>(_exception))
message = message.replace(QString::fromStdString(*location->sourceName), contract->contract()->name()); //substitute the location to match our contract names {
compilationError(message, QString::fromStdString(*location->sourceName)); if (location->sourceName)
sourceName = QString::fromStdString(*location->sourceName);
if (!sourceName.isEmpty())
if (CompiledContract* contract = contractByDocumentId(sourceName))
//substitute the location to match our contract names
message = message.replace(sourceName, contract->contract()->name());
}
compilationError(message, sourceName);
} }
m_compiling = false; m_compiling = false;
emit stateChanged(); emit stateChanged();

2
mix/ContractCallDataEncoder.cpp

@ -127,7 +127,7 @@ unsigned ContractCallDataEncoder::encodeSingleItem(QString const& _data, Solidit
} }
} }
unsigned dataSize = _type.dynamicSize ? result.size() : alignSize; size_t dataSize = _type.dynamicSize ? result.size() : alignSize;
if (result.size() % alignSize != 0) if (result.size() % alignSize != 0)
result.resize((result.size() & ~(alignSize - 1)) + alignSize); result.resize((result.size() & ~(alignSize - 1)) + alignSize);
_dest.insert(_dest.end(), result.begin(), result.end()); _dest.insert(_dest.end(), result.begin(), result.end());

3
mix/FileIo.cpp

@ -102,6 +102,7 @@ void FileIo::writeFile(QString const& _url, QString const& _data)
} }
else else
error(tr("Error writing file %1").arg(_url)); error(tr("Error writing file %1").arg(_url));
file.close();
m_watcher->addPath(path); m_watcher->addPath(path);
} }
@ -184,7 +185,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
QUrl url(_deploymentFolder + "package.dapp"); QUrl url(_deploymentFolder + "package.dapp");
QFile compressed(url.path()); QFile compressed(url.path());
QByteArray qFileBytes((char*)dapp.data(), dapp.size()); QByteArray qFileBytes((char*)dapp.data(), static_cast<int>(dapp.size()));
if (compressed.open(QIODevice::WriteOnly)) if (compressed.open(QIODevice::WriteOnly))
{ {
compressed.write(qFileBytes); compressed.write(qFileBytes);

3
mix/MixClient.cpp

@ -40,7 +40,7 @@ namespace mix
{ {
Secret const c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074"); Secret const c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
u256 const c_mixGenesisDifficulty = c_minimumDifficulty; //TODO: make it lower for Mix somehow u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix somehow
bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) bytes MixBlockChain::createGenesisBlock(h256 _stateRoot)
{ {
@ -117,6 +117,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256();
State execState = _state; State execState = _state;
execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation
Executive execution(execState, lastHashes, 0); Executive execution(execState, lastHashes, 0);
execution.initialize(&rlp); execution.initialize(&rlp);
execution.execute(); execution.execute();

14
mix/qml/WebPreview.qml

@ -377,7 +377,7 @@ Item {
font.italic: true font.italic: true
font.pointSize: appStyle.absoluteSize(-3) font.pointSize: appStyle.absoluteSize(-3)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
property bool active: false
property var history: [] property var history: []
property int index: -1 property int index: -1
@ -394,12 +394,20 @@ Item {
expressionInput.text = history[index]; expressionInput.text = history[index];
} }
onTextChanged: {
active = text !== "";
if (!active)
index = -1;
}
Keys.onDownPressed: { Keys.onDownPressed: {
displayCache(1); if (active)
displayCache(-1);
} }
Keys.onUpPressed: { Keys.onUpPressed: {
displayCache(-1); displayCache(1);
active = true;
} }
Keys.onEnterPressed: Keys.onEnterPressed:

4
mix/qml/html/cm/errorannotation.js

@ -23,13 +23,13 @@ ErrorAnnotation.prototype.init = function()
ErrorAnnotation.prototype.open = function() ErrorAnnotation.prototype.open = function()
{ {
if (this.errorMark.find()) if (this.line)
{ {
var node = document.createElement("div"); var node = document.createElement("div");
node.id = "annotation" node.id = "annotation"
node.innerHTML = this.content; node.innerHTML = this.content;
node.className = "CodeMirror-errorannotation-context"; node.className = "CodeMirror-errorannotation-context";
this.lineWidget = this.editor.addLineWidget(this.errorMark.find().from.line, node, { coverGutter: false }); this.lineWidget = this.editor.addLineWidget(this.line, node, { coverGutter: false });
this.opened = true; this.opened = true;
} }
} }

10
mix/test/qml/TestMain.qml

@ -58,11 +58,20 @@ TestCase
ts.keyPressChar(mainApplication, "S", Qt.ControlModifier, 200); //Ctrl+S ts.keyPressChar(mainApplication, "S", Qt.ControlModifier, 200); //Ctrl+S
} }
function waitForMining()
{
while (mainApplication.clientModel.mining)
ts.waitForSignal(mainApplication.clientModel, "miningComplete()", 5000);
wait(1); //allow events to propagate 2 times for transaction log to be updated
wait(1);
}
function waitForExecution() function waitForExecution()
{ {
while (mainApplication.clientModel.running) while (mainApplication.clientModel.running)
ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000); ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000);
wait(1); //allow events to propagate 2 times for transaction log to be updated
wait(1);
} }
function editHtml(c) function editHtml(c)
@ -89,6 +98,7 @@ TestCase
function test_dbg_vm() { TestDebugger.test_vmDebugging(); } function test_dbg_vm() { TestDebugger.test_vmDebugging(); }
function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); } function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); }
function test_miner_selectMiner() { TestMiner.test_selectMiner(); } function test_miner_selectMiner() { TestMiner.test_selectMiner(); }
function test_miner_mine() { TestMiner.test_mine(); }
function test_project_contractRename() { TestProject.test_contractRename(); } function test_project_contractRename() { TestProject.test_contractRename(); }
} }

5
mix/test/qml/js/TestDebugger.js

@ -91,17 +91,20 @@ function test_arrayParametersAndStorage()
" {\r" + " {\r" +
" m = x;\r" + " m = x;\r" +
" s = 5;\r" + " s = 5;\r" +
" signed = 6534;\r" +
" }\r" + " }\r" +
" \r" + " \r" +
" function setMV(uint72[5] x) external\r" + " function setMV(uint72[5] x) external\r" +
" {\r" + " {\r" +
" mv = x;\r" + " mv = x;\r" +
" s = 42;\r" + " s = 42;\r" +
" signed = -534;\r" +
" }\r" + " }\r" +
" \r" + " \r" +
" uint256[] m;\r" + " uint256[] m;\r" +
" uint72[5] mv;\r" + " uint72[5] mv;\r" +
" uint256 s;\r" + " uint256 s;\r" +
" int48 signed;\r" +
" }\r"); " }\r");
mainApplication.projectModel.stateListModel.editState(0); mainApplication.projectModel.stateListModel.editState(0);
@ -127,11 +130,13 @@ function test_arrayParametersAndStorage()
mainApplication.mainContent.rightPane.debugSlider.value = mainApplication.mainContent.rightPane.debugSlider.maximumValue; mainApplication.mainContent.rightPane.debugSlider.value = mainApplication.mainContent.rightPane.debugSlider.maximumValue;
tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "m", ["4","5","6","2","10"]); tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "m", ["4","5","6","2","10"]);
tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "s", "5"); tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "s", "5");
tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "signed", "6534");
//debug setMV //debug setMV
mainApplication.clientModel.debugRecord(4); mainApplication.clientModel.debugRecord(4);
mainApplication.mainContent.rightPane.debugSlider.value = mainApplication.mainContent.rightPane.debugSlider.maximumValue - 1; mainApplication.mainContent.rightPane.debugSlider.value = mainApplication.mainContent.rightPane.debugSlider.maximumValue - 1;
tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "mv", ["13","35","1","4","0"]); tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "mv", ["13","35","1","4","0"]);
tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "s", "42"); tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "s", "42");
tryCompare(mainApplication.mainContent.rightPane.solStorage.item.value, "signed", "-534");
tryCompare(mainApplication.mainContent.rightPane.solCallStack.listModel, 0, "setMV"); tryCompare(mainApplication.mainContent.rightPane.solCallStack.listModel, 0, "setMV");
} }

10
mix/test/qml/js/TestMiner.js

@ -18,3 +18,13 @@ function test_selectMiner()
compare(state.miner.secret, account.secret); compare(state.miner.secret, account.secret);
} }
function test_mine()
{
newProject();
mainApplication.mainContent.startQuickDebugging();
waitForExecution();
mainApplication.clientModel.mine();
waitForMining();
tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(3), "contract", " - Block - ");
}

4
mix/test/qml/js/TestProject.js

@ -1,11 +1,12 @@
function test_contractRename() function test_contractRename()
{ {
newProject(); newProject();
waitForExecution();
tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Contract"); tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Contract");
editContract("contract Renamed {}"); editContract("contract Renamed {}");
mainApplication.mainContent.startQuickDebugging(); mainApplication.mainContent.startQuickDebugging();
waitForExecution(); waitForExecution();
wait(1000); tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(2), "contract", "Renamed");
tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Renamed"); tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Renamed");
mainApplication.projectModel.stateListModel.editState(0); mainApplication.projectModel.stateListModel.editState(0);
mainApplication.projectModel.stateDialog.model.editTransaction(2); mainApplication.projectModel.stateDialog.model.editTransaction(2);
@ -14,5 +15,4 @@ function test_contractRename()
tryCompare(transactionDialog, "functionId", "Renamed"); tryCompare(transactionDialog, "functionId", "Renamed");
transactionDialog.close(); transactionDialog.close();
mainApplication.projectModel.stateDialog.close(); mainApplication.projectModel.stateDialog.close();
tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(2), "contract", "Renamed");
} }

26
solc/CommandLineInterface.cpp

@ -55,6 +55,7 @@ namespace solidity
static string const g_argAbiStr = "json-abi"; static string const g_argAbiStr = "json-abi";
static string const g_argSolAbiStr = "sol-abi"; static string const g_argSolAbiStr = "sol-abi";
static string const g_argAsmStr = "asm"; static string const g_argAsmStr = "asm";
static string const g_argAsmJsonStr = "asm-json";
static string const g_argAstStr = "ast"; static string const g_argAstStr = "ast";
static string const g_argAstJson = "ast-json"; static string const g_argAstJson = "ast-json";
static string const g_argBinaryStr = "binary"; static string const g_argBinaryStr = "binary";
@ -80,10 +81,15 @@ static bool needStdout(po::variables_map const& _args)
{ {
return return
argToStdout(_args, g_argAbiStr) || argToStdout(_args, g_argSolAbiStr) || argToStdout(_args, g_argAbiStr) ||
argToStdout(_args, g_argNatspecUserStr) || argToStdout(_args, g_argAstJson) || argToStdout(_args, g_argSolAbiStr) ||
argToStdout(_args, g_argNatspecDevStr) || argToStdout(_args, g_argAsmStr) || argToStdout(_args, g_argNatspecUserStr) ||
argToStdout(_args, g_argOpcodesStr) || argToStdout(_args, g_argBinaryStr); argToStdout(_args, g_argAstJson) ||
argToStdout(_args, g_argNatspecDevStr) ||
argToStdout(_args, g_argAsmStr) ||
argToStdout(_args, g_argAsmJsonStr) ||
argToStdout(_args, g_argOpcodesStr) ||
argToStdout(_args, g_argBinaryStr);
} }
static inline bool outputToFile(OutputType type) static inline bool outputToFile(OutputType type)
@ -220,6 +226,8 @@ bool CommandLineInterface::parseArguments(int argc, char** argv)
"Request to output the AST of the contract in JSON format.") "Request to output the AST of the contract in JSON format.")
(g_argAsmStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"), (g_argAsmStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the EVM assembly of the contract.") "Request to output the EVM assembly of the contract.")
(g_argAsmJsonStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the EVM assembly of the contract in JSON format.")
(g_argOpcodesStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"), (g_argOpcodesStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the Opcodes of the contract.") "Request to output the Opcodes of the contract.")
(g_argBinaryStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"), (g_argBinaryStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
@ -411,19 +419,19 @@ void CommandLineInterface::actOnInput()
cout << endl << "======= " << contract << " =======" << endl; cout << endl << "======= " << contract << " =======" << endl;
// do we need EVM assembly? // do we need EVM assembly?
if (m_args.count(g_argAsmStr)) if (m_args.count(g_argAsmStr) || m_args.count(g_argAsmJsonStr))
{ {
auto choice = m_args[g_argAsmStr].as<OutputType>(); auto choice = m_args.count(g_argAsmStr) ? m_args[g_argAsmStr].as<OutputType>() : m_args[g_argAsmJsonStr].as<OutputType>();
if (outputToStdout(choice)) if (outputToStdout(choice))
{ {
cout << "EVM assembly:" << endl; cout << "EVM assembly:" << endl;
m_compiler->streamAssembly(cout, contract, m_sourceCodes); m_compiler->streamAssembly(cout, contract, m_sourceCodes, m_args.count(g_argAsmJsonStr));
} }
if (outputToFile(choice)) if (outputToFile(choice))
{ {
ofstream outFile(contract + ".evm"); ofstream outFile(contract + (m_args.count(g_argAsmJsonStr) ? "_evm.json" : ".evm"));
m_compiler->streamAssembly(outFile, contract, m_sourceCodes); m_compiler->streamAssembly(outFile, contract, m_sourceCodes, m_args.count(g_argAsmJsonStr));
outFile.close(); outFile.close();
} }
} }

23
test/SolidityEndToEndTest.cpp

@ -3676,6 +3676,29 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_with_bytes0)
BOOST_CHECK(callContractFunction("test()") == encodeArgs(true)); BOOST_CHECK(callContractFunction("test()") == encodeArgs(true));
} }
BOOST_AUTO_TEST_CASE(packed_storage_signed)
{
char const* sourceCode = R"(
contract C {
int8 a;
uint8 b;
int8 c;
uint8 d;
function test() returns (uint x1, uint x2, uint x3, uint x4) {
a = -2;
b = -uint8(a) * 2;
c = a * int8(120) * int8(121);
x1 = uint(a);
x2 = b;
x3 = uint(c);
x4 = d;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK( callContractFunction("test()") == encodeArgs(u256(-2), u256(4), u256(-112), u256(0)));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

37
test/SolidityNameAndTypeResolution.cpp

@ -407,6 +407,39 @@ BOOST_AUTO_TEST_CASE(create_abstract_contract)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
} }
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional)
{
ASTPointer<SourceUnit> sourceUnit;
char const* text = R"(
contract BaseBase { function BaseBase(uint j); }
contract base is BaseBase { function foo(); }
contract derived is base {
function derived(uint i) BaseBase(i){}
function foo() {}
}
)";
ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(text), "Parsing and name resolving failed");
}
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided)
{
ASTPointer<SourceUnit> sourceUnit;
char const* text = R"(
contract BaseBase { function BaseBase(uint j); }
contract base is BaseBase { function foo(); }
contract derived is base {
function derived(uint i) {}
function foo() {}
}
)";
ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name resolving failed");
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->getNodes();
BOOST_CHECK_EQUAL(nodes.size(), 3);
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
BOOST_CHECK(derived);
BOOST_CHECK(!derived->isFullyImplemented());
}
BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract) BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract)
{ {
ASTPointer<SourceUnit> sourceUnit; ASTPointer<SourceUnit> sourceUnit;
@ -665,7 +698,7 @@ BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments)
contract A { function A(uint a) { } } contract A { function A(uint a) { } }
contract B is A { } contract B is A { }
)"; )";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(base_constructor_arguments_override) BOOST_AUTO_TEST_CASE(base_constructor_arguments_override)
@ -674,7 +707,7 @@ BOOST_AUTO_TEST_CASE(base_constructor_arguments_override)
contract A { function A(uint a) { } } contract A { function A(uint a) { } }
contract B is A { } contract B is A { }
)"; )";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion) BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)

80
test/SolidityOptimizer.cpp

@ -28,6 +28,7 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <test/solidityExecutionFramework.h> #include <test/solidityExecutionFramework.h>
#include <libevmcore/CommonSubexpressionEliminator.h> #include <libevmcore/CommonSubexpressionEliminator.h>
#include <libevmcore/ControlFlowGraph.h>
#include <libevmcore/Assembly.h> #include <libevmcore/Assembly.h>
using namespace std; using namespace std;
@ -96,6 +97,18 @@ public:
BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end()); BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
} }
void checkCFG(AssemblyItems const& _input, AssemblyItems const& _expectation)
{
AssemblyItems output = _input;
// Running it four times should be enough for these tests.
for (unsigned i = 0; i < 4; ++i)
{
eth::ControlFlowGraph cfg(output);
output = cfg.optimisedItems();
}
BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
}
protected: protected:
Address m_optimizedContract; Address m_optimizedContract;
Address m_nonOptimizedContract; Address m_nonOptimizedContract;
@ -731,6 +744,73 @@ 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_CHECK_EQUAL(1, count(output.begin(), output.end(), AssemblyItem(Instruction::SHA3)));
} }
BOOST_AUTO_TEST_CASE(control_flow_graph_remove_unused)
{
// remove parts of the code that are unused
AssemblyItems input{
AssemblyItem(PushTag, 1),
Instruction::JUMP,
u256(7),
AssemblyItem(Tag, 1),
};
checkCFG(input, {});
}
BOOST_AUTO_TEST_CASE(control_flow_graph_remove_unused_loop)
{
AssemblyItems input{
AssemblyItem(PushTag, 3),
Instruction::JUMP,
AssemblyItem(Tag, 1),
u256(7),
AssemblyItem(PushTag, 2),
Instruction::JUMP,
AssemblyItem(Tag, 2),
u256(8),
AssemblyItem(PushTag, 1),
Instruction::JUMP,
AssemblyItem(Tag, 3),
u256(11)
};
checkCFG(input, {u256(11)});
}
BOOST_AUTO_TEST_CASE(control_flow_graph_reconnect_single_jump_source)
{
// move code that has only one unconditional jump source
AssemblyItems input{
u256(1),
AssemblyItem(PushTag, 1),
Instruction::JUMP,
AssemblyItem(Tag, 2),
u256(2),
AssemblyItem(PushTag, 3),
Instruction::JUMP,
AssemblyItem(Tag, 1),
u256(3),
AssemblyItem(PushTag, 2),
Instruction::JUMP,
AssemblyItem(Tag, 3),
u256(4),
};
checkCFG(input, {u256(1), u256(3), u256(2), u256(4)});
}
BOOST_AUTO_TEST_CASE(control_flow_graph_do_not_remove_returned_to)
{
// do not remove parts that are "returned to"
AssemblyItems input{
AssemblyItem(PushTag, 1),
AssemblyItem(PushTag, 2),
Instruction::JUMP,
AssemblyItem(Tag, 2),
Instruction::JUMP,
AssemblyItem(Tag, 1),
u256(2)
};
checkCFG(input, {u256(2)});
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

32
test/TestHelper.cpp

@ -119,6 +119,32 @@ ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller):
} }
} }
json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o)
{
static const set<string> hashes {"bloom" , "coinbase", "hash", "mixHash", "parentHash", "receiptTrie",
"stateRoot", "transactionsTrie", "uncleHash", "currentCoinbase",
"previousHash", "to", "address", "caller", "origin", "secretKey"};
for (auto& i: _o)
{
std::string key = i.first;
if (hashes.count(key))
continue;
std::string str;
json_spirit::mValue value = i.second;
if (value.type() == json_spirit::int_type)
str = toString(value.get_int());
else if (value.type() == json_spirit::str_type)
str = value.get_str();
else continue;
_o[key] = (str.substr(0, 2) == "0x") ? str : "0x" + toHex(toCompactBigEndian(toInt(str)));
}
return _o;
}
void ImportTest::importEnv(json_spirit::mObject& _o) void ImportTest::importEnv(json_spirit::mObject& _o)
{ {
assert(_o.count("previousHash") > 0); assert(_o.count("previousHash") > 0);
@ -325,6 +351,8 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost)
// export pre state // export pre state
m_TestObject["pre"] = fillJsonWithState(m_statePre); m_TestObject["pre"] = fillJsonWithState(m_statePre);
m_TestObject["env"] = makeAllFieldsHex(m_TestObject["env"].get_obj());
m_TestObject["transaction"] = makeAllFieldsHex(m_TestObject["transaction"].get_obj());
} }
json_spirit::mObject fillJsonWithState(State _state) json_spirit::mObject fillJsonWithState(State _state)
@ -335,8 +363,8 @@ json_spirit::mObject fillJsonWithState(State _state)
for (auto const& a: _state.addresses()) for (auto const& a: _state.addresses())
{ {
json_spirit::mObject o; json_spirit::mObject o;
o["balance"] = toString(_state.balance(a.first)); o["balance"] = "0x" + toHex(toCompactBigEndian(_state.balance(a.first)));
o["nonce"] = toString(_state.transactionsFrom(a.first)); o["nonce"] = "0x" + toHex(toCompactBigEndian(_state.transactionsFrom(a.first)));
{ {
json_spirit::mObject store; json_spirit::mObject store;
for (auto const& s: _state.storage(a.first)) for (auto const& s: _state.storage(a.first))

1
test/TestHelper.h

@ -121,6 +121,7 @@ public:
static void importState(json_spirit::mObject& _o, eth::State& _state); static void importState(json_spirit::mObject& _o, eth::State& _state);
static void importState(json_spirit::mObject& _o, eth::State& _state, stateOptionsMap& _stateOptionsMap); static void importState(json_spirit::mObject& _o, eth::State& _state, stateOptionsMap& _stateOptionsMap);
void importTransaction(json_spirit::mObject& _o); void importTransaction(json_spirit::mObject& _o);
static json_spirit::mObject& makeAllFieldsHex(json_spirit::mObject& _o);
void exportTest(bytes const& _output, eth::State const& _statePost); void exportTest(bytes const& _output, eth::State const& _statePost);
static void checkExpectedState(eth::State const& _stateExpect, eth::State const& _statePost, stateOptionsMap const _expectedStateOptions = stateOptionsMap(), WhenError _throw = WhenError::Throw); static void checkExpectedState(eth::State const& _stateExpect, eth::State const& _statePost, stateOptionsMap const _expectedStateOptions = stateOptionsMap(), WhenError _throw = WhenError::Throw);

18
test/blockchain.cpp

@ -90,7 +90,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
for (auto const& bl: o["blocks"].get_array()) for (auto const& bl: o["blocks"].get_array())
{ {
mObject blObj = bl.get_obj(); mObject blObj = bl.get_obj();
stateTemp = state;
// get txs // get txs
TransactionQueue txs; TransactionQueue txs;
ZeroGasPricer gp; ZeroGasPricer gp;
@ -222,6 +222,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
txObject["v"] = to_string(txi.second.signature().v + 27); txObject["v"] = to_string(txi.second.signature().v + 27);
txObject["to"] = txi.second.isCreation() ? "" : toString(txi.second.receiveAddress()); txObject["to"] = txi.second.isCreation() ? "" : toString(txi.second.receiveAddress());
txObject["value"] = toString(txi.second.value()); txObject["value"] = toString(txi.second.value());
txObject = ImportTest::makeAllFieldsHex(txObject);
txArray.push_back(txObject); txArray.push_back(txObject);
} }
@ -301,6 +302,11 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
o["blocks"] = blArray; o["blocks"] = blArray;
o["postState"] = fillJsonWithState(state); o["postState"] = fillJsonWithState(state);
//make all values hex
State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress);
importer.importState(o["pre"].get_obj(), prestate);
o["pre"] = fillJsonWithState(prestate);
}//_fillin }//_fillin
else else
@ -619,11 +625,11 @@ void writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi)
_o["transactionsTrie"] = toString(_bi.transactionsRoot); _o["transactionsTrie"] = toString(_bi.transactionsRoot);
_o["receiptTrie"] = toString(_bi.receiptsRoot); _o["receiptTrie"] = toString(_bi.receiptsRoot);
_o["bloom"] = toString(_bi.logBloom); _o["bloom"] = toString(_bi.logBloom);
_o["difficulty"] = toString(_bi.difficulty); _o["difficulty"] = "0x" + toHex(toCompactBigEndian(_bi.difficulty));
_o["number"] = toString(_bi.number); _o["number"] = "0x" + toHex(toCompactBigEndian(_bi.number));
_o["gasLimit"] = toString(_bi.gasLimit); _o["gasLimit"] = "0x" + toHex(toCompactBigEndian(_bi.gasLimit));
_o["gasUsed"] = toString(_bi.gasUsed); _o["gasUsed"] = "0x" + toHex(toCompactBigEndian(_bi.gasUsed));
_o["timestamp"] = toString(_bi.timestamp); _o["timestamp"] = "0x" + toHex(toCompactBigEndian(_bi.timestamp));
_o["extraData"] ="0x" + toHex(_bi.extraData); _o["extraData"] ="0x" + toHex(_bi.extraData);
_o["mixHash"] = toString(_bi.mixHash); _o["mixHash"] = toString(_bi.mixHash);
_o["nonce"] = toString(_bi.nonce); _o["nonce"] = toString(_bi.nonce);

45
test/net.cpp

@ -32,7 +32,13 @@ using namespace dev::p2p;
namespace ba = boost::asio; namespace ba = boost::asio;
namespace bi = ba::ip; namespace bi = ba::ip;
BOOST_AUTO_TEST_SUITE(net) struct NetFixture
{
NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; }
~NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; }
};
BOOST_FIXTURE_TEST_SUITE(net, NetFixture)
/** /**
* Only used for testing. Not useful beyond tests. * Only used for testing. Not useful beyond tests.
@ -53,7 +59,7 @@ protected:
struct TestNodeTable: public NodeTable struct TestNodeTable: public NodeTable
{ {
/// Constructor /// Constructor
TestNodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30300): NodeTable(_io, _alias, _addr, _port) {} TestNodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30300): NodeTable(_io, _alias, NodeIPEndpoint(_addr, _port, _port)) {}
static std::vector<std::pair<KeyPair,unsigned>> createTestNodes(unsigned _count) static std::vector<std::pair<KeyPair,unsigned>> createTestNodes(unsigned _count)
{ {
@ -93,7 +99,7 @@ struct TestNodeTable: public NodeTable
// manually add node for test // manually add node for test
{ {
Guard ln(x_nodes); Guard ln(x_nodes);
shared_ptr<NodeEntry> node(new NodeEntry(m_node, n.first.pub(), NodeIPEndpoint(bi::udp::endpoint(ourIp, n.second), bi::tcp::endpoint(ourIp, n.second)))); shared_ptr<NodeEntry> node(new NodeEntry(m_node, n.first.pub(), NodeIPEndpoint(ourIp, n.second, n.second)));
node->pending = false; node->pending = false;
m_nodes[node->id] = node; m_nodes[node->id] = node;
} }
@ -240,7 +246,7 @@ BOOST_AUTO_TEST_CASE(neighboursPacketLength)
{ {
Neighbours::Node node; Neighbours::Node node;
node.ipAddress = boost::asio::ip::address::from_string("200.200.200.200").to_string(); node.ipAddress = boost::asio::ip::address::from_string("200.200.200.200").to_string();
node.port = testNodes[i].second; node.udpPort = testNodes[i].second;
node.node = testNodes[i].first.pub(); node.node = testNodes[i].first.pub();
out.nodes.push_back(node); out.nodes.push_back(node);
} }
@ -261,7 +267,7 @@ BOOST_AUTO_TEST_CASE(test_neighbours_packet)
{ {
Neighbours::Node node; Neighbours::Node node;
node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string(); node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string();
node.port = n.second; node.udpPort = n.second;
node.node = n.first.pub(); node.node = n.first.pub();
out.nodes.push_back(node); out.nodes.push_back(node);
} }
@ -273,7 +279,7 @@ BOOST_AUTO_TEST_CASE(test_neighbours_packet)
int count = 0; int count = 0;
for (auto n: in.nodes) for (auto n: in.nodes)
{ {
BOOST_REQUIRE_EQUAL(testNodes[count].second, n.port); BOOST_REQUIRE_EQUAL(testNodes[count].second, n.udpPort);
BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node); BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node);
BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node)); BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node));
count++; count++;
@ -337,3 +343,30 @@ BOOST_AUTO_TEST_CASE(test_udp_once)
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(netTypes)
BOOST_AUTO_TEST_CASE(unspecifiedNode)
{
Node n = UnspecifiedNode;
BOOST_REQUIRE(!n);
Node node(Public(sha3("0")), NodeIPEndpoint(bi::address(), 0, 0));
BOOST_REQUIRE(node);
BOOST_REQUIRE(n != node);
Node nodeEq(Public(sha3("0")), NodeIPEndpoint(bi::address(), 0, 0));
BOOST_REQUIRE_EQUAL(node, nodeEq);
}
BOOST_AUTO_TEST_CASE(nodeTableReturnsUnspecifiedNode)
{
ba::io_service io;
NodeTable t(io, KeyPair::create(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30303, 30303));
if (Node n = t.node(NodeId()))
BOOST_REQUIRE(false);
else
BOOST_REQUIRE(n == UnspecifiedNode);
}
BOOST_AUTO_TEST_SUITE_END()

47
test/peer.cpp

@ -28,7 +28,13 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
BOOST_AUTO_TEST_SUITE(p2p) struct P2PFixture
{
P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; }
~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; }
};
BOOST_FIXTURE_TEST_SUITE(p2p, P2PFixture)
BOOST_AUTO_TEST_CASE(host) BOOST_AUTO_TEST_CASE(host)
{ {
@ -45,7 +51,7 @@ BOOST_AUTO_TEST_CASE(host)
auto node2 = host2.id(); auto node2 = host2.id();
host2.start(); host2.start();
host1.addNode(node2, bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort); host1.addNode(node2, NodeIPEndpoint(bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort));
this_thread::sleep_for(chrono::seconds(3)); this_thread::sleep_for(chrono::seconds(3));
@ -82,11 +88,11 @@ BOOST_AUTO_TEST_CASE(save_nodes)
Host& host = *hosts.front(); Host& host = *hosts.front();
for (auto const& h: hosts) for (auto const& h: hosts)
host.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()); host.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()));
Host& host2 = *hosts.back(); Host& host2 = *hosts.back();
for (auto const& h: hosts) for (auto const& h: hosts)
host2.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()); host2.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()));
this_thread::sleep_for(chrono::milliseconds(2000)); this_thread::sleep_for(chrono::milliseconds(2000));
bytes firstHostNetwork(host.saveNetwork()); bytes firstHostNetwork(host.saveNetwork());
@ -101,7 +107,36 @@ BOOST_AUTO_TEST_CASE(save_nodes)
BOOST_REQUIRE(r.itemCount() == 3); BOOST_REQUIRE(r.itemCount() == 3);
BOOST_REQUIRE(r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion); BOOST_REQUIRE(r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion);
BOOST_REQUIRE_EQUAL(r[1].toBytes().size(), 32); // secret BOOST_REQUIRE_EQUAL(r[1].toBytes().size(), 32); // secret
BOOST_REQUIRE_EQUAL(r[2].itemCount(), 5); BOOST_REQUIRE(r[2].itemCount() >= 5);
for (auto i: r[2])
{
BOOST_REQUIRE(i.itemCount() == 3 || i.itemCount() == 10);
BOOST_REQUIRE(i[0].itemCount() == 4 || i[0].itemCount() == 16);
}
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(peerTypes)
BOOST_AUTO_TEST_CASE(emptySharedPeer)
{
shared_ptr<Peer> p;
BOOST_REQUIRE(!p);
std::map<NodeId, std::shared_ptr<Peer>> peers;
p = peers[NodeId()];
BOOST_REQUIRE(!p);
p.reset(new Peer(UnspecifiedNode));
BOOST_REQUIRE(!p->id);
BOOST_REQUIRE(!*p);
p.reset(new Peer(Node(NodeId(EmptySHA3), UnspecifiedNodeIPEndpoint)));
BOOST_REQUIRE(!(!*p));
BOOST_REQUIRE(*p);
BOOST_REQUIRE(p);
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
@ -131,7 +166,7 @@ int peerTest(int argc, char** argv)
Host ph("Test", NetworkPreferences(listenPort)); Host ph("Test", NetworkPreferences(listenPort));
if (!remoteHost.empty() && !remoteAlias) if (!remoteHost.empty() && !remoteAlias)
ph.addNode(remoteAlias, bi::address::from_string(remoteHost), remotePort, remotePort); ph.addNode(remoteAlias, NodeIPEndpoint(bi::address::from_string(remoteHost), remotePort, remotePort));
this_thread::sleep_for(chrono::milliseconds(200)); this_thread::sleep_for(chrono::milliseconds(200));

2
test/stQuadraticComplexityTestFiller.json

@ -43,7 +43,7 @@
}, },
"transaction" : "transaction" :
{ {
"//" : "run(int256)", "data" : "run(int256)",
"data" : "0x61a47706000000000000000000000000000000000000000000000000000000000000c350", "data" : "0x61a47706000000000000000000000000000000000000000000000000000000000000c350",
"gasLimit" : "904+68*x+e", "gasLimit" : "904+68*x+e",
"gasLimit" : "350000000", "gasLimit" : "350000000",

78
test/stTransactionTestFiller.json

@ -5,7 +5,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -42,7 +42,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -85,7 +85,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -128,7 +128,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -167,7 +167,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -207,7 +207,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -280,7 +280,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1100", "currentGasLimit" : "1100",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -316,7 +316,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "22000", "currentGasLimit" : "22000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -370,7 +370,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "47766", "currentGasLimit" : "47766",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -424,7 +424,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "220000", "currentGasLimit" : "220000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -479,7 +479,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "21100", "currentGasLimit" : "21100",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -515,7 +515,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "21100", "currentGasLimit" : "21100",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -552,7 +552,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "10000000", "currentGasLimit" : "10000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -609,7 +609,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "100000", "currentGasLimit" : "100000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -678,7 +678,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -761,7 +761,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -834,7 +834,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "10000000", "currentGasLimit" : "10000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -925,7 +925,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "10000000", "currentGasLimit" : "10000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1003,7 +1003,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1056,7 +1056,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1110,7 +1110,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1170,7 +1170,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "10000000", "currentGasLimit" : "10000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1226,7 +1226,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "100000", "currentGasLimit" : "100000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1284,7 +1284,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1333,7 +1333,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"post" : { "post" : {
@ -1381,7 +1381,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1417,7 +1417,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "100000000", "currentGasLimit" : "100000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1453,7 +1453,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "10000000", "currentGasLimit" : "10000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1490,7 +1490,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "10000000", "currentGasLimit" : "10000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1533,7 +1533,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "100000000", "currentGasLimit" : "100000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1570,7 +1570,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "10000000", "currentGasLimit" : "10000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1613,7 +1613,7 @@
"currentGasLimit" : "(2**256)-1", "currentGasLimit" : "(2**256)-1",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", "currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1655,7 +1655,7 @@
"currentGasLimit" : "(2**256)-1", "currentGasLimit" : "(2**256)-1",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", "currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1695,7 +1695,7 @@
"currentGasLimit" : "(2**256)-1", "currentGasLimit" : "(2**256)-1",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", "currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1733,7 +1733,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "100000", "currentGasLimit" : "100000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1769,7 +1769,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000000000", "currentGasLimit" : "1000000000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1806,7 +1806,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000000000", "currentGasLimit" : "1000000000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1846,7 +1846,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000000000", "currentGasLimit" : "1000000000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {
@ -1894,7 +1894,7 @@
"currentDifficulty" : "45678256", "currentDifficulty" : "45678256",
"currentGasLimit" : "1000000000000", "currentGasLimit" : "1000000000000",
"currentNumber" : "0", "currentNumber" : "0",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
}, },
"expect" : { "expect" : {

1
test/transaction.cpp

@ -52,6 +52,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
o["sender"] = toString(txFromFields.sender()); o["sender"] = toString(txFromFields.sender());
o["transaction"] = ImportTest::makeAllFieldsHex(tObj);
} }
catch(Exception const& _e) catch(Exception const& _e)
{ {

3
test/tt10mbDataFieldFiller.json

File diff suppressed because one or more lines are too long

2
test/ttTransactionTestFiller.json

@ -176,7 +176,7 @@
}, },
"SenderTest" : { "SenderTest" : {
"//" : "sender 0f65fe9276bc9a24ae7083ae28e2660ef72df99e", "senderExpect" : "sender 0f65fe9276bc9a24ae7083ae28e2660ef72df99e",
"expect" : "valid", "expect" : "valid",
"transaction" : "transaction" :
{ {

4
test/vm.cpp

@ -85,7 +85,7 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map<u256, u256> const& _st
void FakeExtVM::push(mObject& o, string const& _n, u256 _v) void FakeExtVM::push(mObject& o, string const& _n, u256 _v)
{ {
o[_n] = toString(_v); o[_n] = "0x" + toHex(toCompactBigEndian(_v));
} }
void FakeExtVM::push(mArray& a, u256 _v) void FakeExtVM::push(mArray& a, u256 _v)
@ -448,7 +448,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
BOOST_AUTO_TEST_SUITE(VMTests) BOOST_AUTO_TEST_SUITE(VMTests)
BOOST_AUTO_TEST_CASE(vm_tests) BOOST_AUTO_TEST_CASE(vmtests)
{ {
dev::test::executeTests("vmtests", "/VMTests", dev::test::doVMTests); dev::test::executeTests("vmtests", "/VMTests", dev::test::doVMTests);
} }

Loading…
Cancel
Save