Browse Source

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

mix_srci

Conflicts:
	mix/qml/StatusPane.qml
cl-refactor
arkpar 10 years ago
parent
commit
1ddff7d9b7
  1. 1
      alethzero/CMakeLists.txt
  2. 13
      alethzero/MainWin.cpp
  3. 1
      alethzero/MainWin.h
  4. 3
      alethzero/Transact.cpp
  5. 2
      cmake/EthCompilerSettings.cmake
  6. 2
      cmake/FindJsonRpcCpp.cmake
  7. 20
      docker/Dockerfile
  8. 2
      eth/CMakeLists.txt
  9. 88
      eth/main.cpp
  10. 4
      libdevcore/CMakeLists.txt
  11. 194
      libdevcore/StructuredLogger.cpp
  12. 104
      libdevcore/StructuredLogger.h
  13. 46
      libdevcore/UndefMacros.h
  14. 2
      libdevcore/debugbreak.h
  15. 2
      libdevcrypto/CMakeLists.txt
  16. 2
      libethcore/CMakeLists.txt
  17. 14
      libethereum/BlockChain.cpp
  18. 2
      libethereum/BlockChain.h
  19. 7
      libethereum/CMakeLists.txt
  20. 36
      libethereum/Client.cpp
  21. 15
      libethereum/Client.h
  22. 1
      libethereum/EthereumHost.h
  23. 4
      libethereum/EthereumPeer.h
  24. 1
      libethereum/Miner.h
  25. 7
      libethereum/State.cpp
  26. 2
      libethereumx/CMakeLists.txt
  27. 2
      libevm/CMakeLists.txt
  28. 3
      libevm/ExtVMFace.h
  29. 2
      libevmcore/CMakeLists.txt
  30. 2
      libjsqrc/CMakeLists.txt
  31. 9
      libjsqrc/ethereumjs/README.md
  32. 2
      libjsqrc/ethereumjs/bower.json
  33. 140
      libjsqrc/ethereumjs/dist/ethereum.js
  34. 10
      libjsqrc/ethereumjs/dist/ethereum.js.map
  35. 2
      libjsqrc/ethereumjs/dist/ethereum.min.js
  36. 57
      libjsqrc/ethereumjs/lib/abi.js
  37. 11
      libjsqrc/ethereumjs/lib/contract.js
  38. 10
      libjsqrc/ethereumjs/lib/event.js
  39. 42
      libjsqrc/ethereumjs/lib/signature.js
  40. 2
      libjsqrc/ethereumjs/package.json
  41. 203
      libjsqrc/ethereumjs/test/abi.inputParser.js
  42. 2
      liblll/CMakeLists.txt
  43. 3
      libnatspec/CMakeLists.txt
  44. 7
      libp2p/CMakeLists.txt
  45. 3
      libp2p/Common.h
  46. 113
      libp2p/Host.cpp
  47. 66
      libp2p/Host.h
  48. 27
      libp2p/Network.cpp
  49. 96
      libp2p/NodeTable.h
  50. 6
      libp2p/Session.cpp
  51. 3
      libp2p/Session.h
  52. 53
      libp2p/UDP.h
  53. 2
      libserpent/CMakeLists.txt
  54. 2
      libsolidity/CMakeLists.txt
  55. 67
      libsolidity/Compiler.cpp
  56. 17
      libsolidity/ExpressionCompiler.cpp
  57. 1
      libsolidity/Token.h
  58. 13
      libsolidity/Types.cpp
  59. 3
      libsolidity/Types.h
  60. 3
      libweb3jsonrpc/CMakeLists.txt
  61. 3
      libweb3jsonrpc/WebThreeStubServer.cpp
  62. 10
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  63. 3
      libwebthree/CMakeLists.txt
  64. 14
      libwebthree/WebThree.cpp
  65. 16
      libwebthree/WebThree.h
  66. 3
      libwhisper/CMakeLists.txt
  67. 1
      libwhisper/Common.h
  68. 1
      libwhisper/Interface.h
  69. 1
      libwhisper/Message.h
  70. 4
      libwhisper/WhisperHost.cpp
  71. 1
      libwhisper/WhisperHost.h
  72. 1
      libwhisper/WhisperPeer.h
  73. 1
      mix/CMakeLists.txt
  74. 41
      mix/ClientModel.cpp
  75. 11
      mix/ClientModel.h
  76. 3
      mix/DebuggingStateWrapper.h
  77. 3
      mix/Extension.cpp
  78. 22
      mix/MixClient.cpp
  79. 6
      mix/MixClient.h
  80. 1
      mix/QContractDefinition.cpp
  81. 4
      mix/qml/Ether.qml
  82. 151
      mix/qml/StateDialog.qml
  83. 59
      mix/qml/StateListModel.qml
  84. 2
      mix/qml/StatusPane.qml
  85. 33
      mix/qml/TransactionDialog.qml
  86. 6
      mix/qml/TransactionLog.qml
  87. 1
      neth/CMakeLists.txt
  88. 2
      neth/main.cpp
  89. 14
      secp256k1/CMakeLists.txt
  90. 19
      test/SolidityEndToEndTest.cpp
  91. 4
      test/TestHelper.cpp
  92. 4
      test/TestHelper.h
  93. 144
      test/block.cpp
  94. 2
      test/createRandomTest.cpp
  95. 1
      test/fork.cpp
  96. 6
      test/genesis.cpp
  97. 8
      test/hexPrefix.cpp
  98. 37
      test/net.cpp
  99. 146
      test/rlp.cpp
  100. 3
      test/state.cpp

1
alethzero/CMakeLists.txt

@ -13,6 +13,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
qt5_wrap_ui(ui_Main.h Main.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui)

13
alethzero/MainWin.cpp

@ -20,6 +20,10 @@
*/
#include <fstream>
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <QtNetwork/QNetworkReply>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>
@ -1382,11 +1386,16 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "</b>";
else
s << "<br/>Pre: <i>Nothing is before Phil</i>";
BlockReceipts receipts = ethereum()->blockChain().receipts(h);
unsigned ii = 0;
for (auto const& i: block[1])
s << "<br/>" << sha3(i.data()).abridged();// << ": <b>" << i[1].toHash<h256>() << "</b> [<b>" << i[2].toInt<u256>() << "</b> used]";
{
s << "<br/>" << sha3(i.data()).abridged() << ": <b>" << receipts.receipts[ii].stateRoot() << "</b> [<b>" << receipts.receipts[ii].gasUsed() << "</b> used]";
++ii;
}
s << "<br/>Post: <b>" << info.stateRoot << "</b>";
s << "<br/>Dump: " Span(Mono) << toHex(block[0].data()) << "</span>";
s << "<div>Receipts-Hex: " Span(Mono) << toHex(ethereum()->blockChain().receipts(h).rlp()) << "</span></div>";
s << "<div>Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "</span></div>";
}
else
{

1
alethzero/MainWin.h

@ -26,6 +26,7 @@
#endif
#include <map>
#include <QtNetwork/QNetworkAccessManager>
#include <QtCore/QAbstractListModel>
#include <QtCore/QMutex>

3
alethzero/Transact.cpp

@ -19,6 +19,9 @@
* @date 2015
*/
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include "Transact.h"
#include <fstream>

2
cmake/EthCompilerSettings.cmake

@ -3,7 +3,7 @@
# C++11 check and activation
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -DSHAREDLIB -fPIC")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -DSHAREDLIB -fPIC ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")

2
cmake/FindJsonRpcCpp.cmake

@ -14,7 +14,7 @@
# only look in default directories
find_path(
JSON_RPC_CPP_INCLUDE_DIR
NAMES jsonrpccpp/server.h
NAMES jsonrpccpp/server.h jsonrpc/server.h
PATH_SUFFIXES jsonrpc
DOC "json-rpc-cpp include dir"
)

20
docker/Dockerfile

@ -8,23 +8,29 @@ RUN apt-get upgrade -y
RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget
RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 )
RUN apt-get install -qy libncurses5-dev
# Qt-based GUI
# RUN apt-get install -qy qtbase5-dev qt5-default qtdeclarative5-dev libqt5webkit5-dev
RUN apt-get install -qy libncurses5-dev libcurl4-openssl-dev wget
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev libmicrohttpd-dev
# Ethereum PPA
RUN apt-get install -qy software-properties-common
RUN add-apt-repository ppa:ethereum/ethereum
RUN add-apt-repository ppa:ethereum/ethereum-dev
RUN apt-get update
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev
# LLVM-3.5
RUN wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add -
RUN echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main\ndeb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main" > /etc/apt/sources.list.d/llvm-trusty.list
RUN apt-get update
RUN apt-get install -qy llvm-3.5 libedit-dev
# Fix llvm-3.5 cmake paths
RUN mkdir -p /usr/lib/llvm-3.5/share/llvm && ln -s /usr/share/llvm-3.5/cmake /usr/lib/llvm-3.5/share/llvm/cmake
# Build Ethereum (HEADLESS)
RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum
RUN mkdir -p cpp-ethereum/build
RUN cd cpp-ethereum/build && cmake .. -DCMAKE_BUILD_TYPE=Release -DHEADLESS=1 && make -j $(cat /proc/cpuinfo | grep processor | wc -l) && make install
RUN cd cpp-ethereum/build && cmake .. -DHEADLESS=1 -DLLVM_DIR=/usr/share/llvm-3.5/cmake -DEVMJIT=1 && make -j $(cat /proc/cpuinfo | grep processor | wc -l) && make install
RUN ldconfig
ENTRYPOINT ["/usr/local/bin/eth"]

2
eth/CMakeLists.txt

@ -28,7 +28,7 @@ endif()
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1)
if (WIN32)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
endif()

88
eth/main.cpp

@ -25,10 +25,13 @@
#include <fstream>
#include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libethereum/All.h>
@ -97,38 +100,40 @@ void interactiveHelp()
void help()
{
cout
<< "Usage eth [OPTIONS] <remote-host>" << endl
<< "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
<< " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl
<< " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
<< "Usage eth [OPTIONS] <remote-host>" << endl
<< "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
<< " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl
<< " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
#if ETH_JSONRPC
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
#endif
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " --structured-logging Enables structured logging." << endl
<< " --structured-logging-format <time-format> Give time format string for structured logging output." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
#if ETH_EVMJIT
<< " --jit Use EVM JIT (default: off)." << endl
<< " --jit Use EVM JIT (default: off)." << endl
#endif
;
exit(0);
exit(0);
}
string credits(bool _interactive = false)
@ -207,6 +212,8 @@ int main(int argc, char** argv)
bool useLocal = false;
bool forceMining = false;
bool jit = false;
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string clientName;
// Init defaults
@ -279,6 +286,10 @@ int main(int argc, char** argv)
}
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc)
us = KeyPair(h256(fromHex(argv[++i])));
else if (arg == "--structured-logging-format" && i + 1 < argc)
structuredLoggingFormat = string(argv[++i]);
else if (arg == "--structured-logging")
structuredLogging = true;
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i];
else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
@ -350,11 +361,13 @@ int main(int argc, char** argv)
cout << credits();
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3(
"Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""),
clientImplString,
dbPath,
false,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
@ -364,7 +377,7 @@ int main(int argc, char** argv)
);
web3.setIdealPeerCount(peers);
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
StructuredLogger::starting(clientImplString, dev::Version);
if (c)
{
c->setForceMining(forceMining);
@ -525,7 +538,7 @@ int main(int argc, char** argv)
string sdata;
iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata;
cnote << "Data:";
cnote << sdata;
bytes data = dev::eth::parseData(sdata);
@ -608,7 +621,7 @@ int main(int argc, char** argv)
if (size > 0)
cwarn << "Invalid address length:" << size;
}
else
else
{
auto const& bc =c->blockChain();
auto h = bc.currentHash();
@ -630,7 +643,7 @@ int main(int argc, char** argv)
cwarn << "transaction rejected";
}
}
}
}
else
cwarn << "Require parameters: send ADDRESS AMOUNT";
}
@ -688,7 +701,7 @@ int main(int argc, char** argv)
cwarn << "Minimum gas amount is" << minGas;
else
c->transact(us.secret(), endowment, init, gas, gasPrice);
}
}
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
}
@ -806,7 +819,7 @@ int main(int argc, char** argv)
string hexSec;
iss >> hexSec;
us = KeyPair(h256(fromHex(hexSec)));
}
}
else
cwarn << "Require parameter: setSecret HEXSECRETKEY";
}
@ -847,7 +860,7 @@ int main(int argc, char** argv)
RLPStream config(2);
config << us.secret() << coinbase;
writeFile(path, config.out());
}
}
else
cwarn << "Require parameter: exportConfig PATH";
}
@ -863,10 +876,10 @@ int main(int argc, char** argv)
RLP config(b);
us = KeyPair(config[0].toHash<Secret>());
coinbase = config[1].toHash<Address>();
}
}
else
cwarn << path << "has no content!";
}
}
else
cwarn << "Require parameter: importConfig PATH";
}
@ -898,6 +911,7 @@ int main(int argc, char** argv)
while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
StructuredLogger::stopping(clientImplString, dev::Version);
auto netData = web3.saveNetwork();
if (!netData.empty())
writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData);

4
libdevcore/CMakeLists.txt

@ -12,6 +12,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
@ -27,6 +28,7 @@ endif()
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES})
# transitive dependencies for windows executables
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
@ -42,6 +44,6 @@ elseif (UNIX)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif()
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

194
libdevcore/StructuredLogger.cpp

@ -0,0 +1,194 @@
/*
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 StructuredLogger.h
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*
* A simple helper class for the structured logging
*/
#include "StructuredLogger.h"
#include <ctime>
#include <json/json.h>
#include "Guards.h"
using namespace std;
namespace dev
{
string StructuredLogger::timePointToString(chrono::system_clock::time_point const& _ts)
{
// not using C++11 std::put_time due to gcc bug
// http://stackoverflow.com/questions/14136833/stdput-time-implementation-status-in-gcc
char buffer[64];
time_t time = chrono::system_clock::to_time_t(_ts);
tm* ptm = localtime(&time);
if (strftime(buffer, sizeof(buffer), get().m_timeFormat.c_str(), ptm))
return string(buffer);
return "";
}
void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const
{
Json::Value event;
static Mutex s_lock;
Guard l(s_lock);
event[_name] = _value;
cout << event << endl << flush;
}
void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion)
{
if (get().m_enabled)
{
Json::Value event;
event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion);
event["ts"] = timePointToString(std::chrono::system_clock::now());
get().outputJson(event, "starting");
}
}
void StructuredLogger::stopping(string const& _clientImpl, const char* _ethVersion)
{
if (get().m_enabled)
{
Json::Value event;
event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion);
event["ts"] = timePointToString(std::chrono::system_clock::now());
get().outputJson(event, "stopping");
}
}
void StructuredLogger::p2pConnected(
string const& _id,
bi::tcp::endpoint const& _addr,
chrono::system_clock::time_point const& _ts,
string const& _remoteVersion,
unsigned int _numConnections)
{
if (get().m_enabled)
{
std::stringstream addrStream;
addrStream << _addr;
Json::Value event;
event["remote_version_string"] = _remoteVersion;
event["remote_addr"] = addrStream.str();
event["remote_id"] = _id;
event["num_connections"] = Json::Value(_numConnections);
event["ts"] = timePointToString(_ts);
get().outputJson(event, "p2p.connected");
}
}
void StructuredLogger::p2pDisconnected(string const& _id, bi::tcp::endpoint const& _addr, unsigned int _numConnections)
{
if (get().m_enabled)
{
std::stringstream addrStream;
addrStream << _addr;
Json::Value event;
event["remote_addr"] = addrStream.str();
event["remote_id"] = _id;
event["num_connections"] = Json::Value(_numConnections);
event["ts"] = timePointToString(chrono::system_clock::now());
get().outputJson(event, "p2p.disconnected");
}
}
void StructuredLogger::minedNewBlock(
string const& _hash,
string const& _blockNumber,
string const& _chainHeadHash,
string const& _prevHash)
{
if (get().m_enabled)
{
Json::Value event;
event["block_hash"] = _hash;
event["block_number"] = _blockNumber;
event["chain_head_hash"] = _chainHeadHash;
event["ts"] = timePointToString(std::chrono::system_clock::now());
event["block_prev_hash"] = _prevHash;
get().outputJson(event, "eth.miner.new_block");
}
}
void StructuredLogger::chainReceivedNewBlock(
string const& _hash,
string const& _blockNumber,
string const& _chainHeadHash,
string const& _remoteID,
string const& _prevHash)
{
if (get().m_enabled)
{
Json::Value event;
event["block_hash"] = _hash;
event["block_number"] = _blockNumber;
event["chain_head_hash"] = _chainHeadHash;
event["remote_id"] = _remoteID;
event["ts"] = timePointToString(chrono::system_clock::now());
event["block_prev_hash"] = _prevHash;
get().outputJson(event, "eth.chain.received.new_block");
}
}
void StructuredLogger::chainNewHead(
string const& _hash,
string const& _blockNumber,
string const& _chainHeadHash,
string const& _prevHash)
{
if (get().m_enabled)
{
Json::Value event;
event["block_hash"] = _hash;
event["block_number"] = _blockNumber;
event["chain_head_hash"] = _chainHeadHash;
event["ts"] = timePointToString(chrono::system_clock::now());
event["block_prev_hash"] = _prevHash;
get().outputJson(event, "eth.miner.new_block");
}
}
void StructuredLogger::transactionReceived(string const& _hash, string const& _remoteId)
{
if (get().m_enabled)
{
Json::Value event;
event["tx_hash"] = _hash;
event["remote_id"] = _remoteId;
event["ts"] = timePointToString(chrono::system_clock::now());
get().outputJson(event, "eth.tx.received");
}
}
}

104
libdevcore/StructuredLogger.h

@ -0,0 +1,104 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file StructuredLogger.h
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*
* A simple helper class for the structured logging
* The spec for the implemented log events is here:
* https://github.com/ethereum/system-testing/wiki/Log-Events
*/
#pragma once
#include <string>
#include <chrono>
#include <libp2p/Network.h>
namespace Json { class Value; }
namespace dev
{
// TODO: Make the output stream configurable. stdout, stderr, file e.t.c.
class StructuredLogger
{
public:
/**
* Initializes the structured logger object
* @param _enabled Whether logging is on or off
* @param _timeFormat A time format string as described here:
* http://en.cppreference.com/w/cpp/chrono/c/strftime
* with which to display timestamps
*/
void initialize(bool _enabled, std::string const& _timeFormat)
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
}
static StructuredLogger& get()
{
static StructuredLogger instance;
return instance;
}
static void starting(std::string const& _clientImpl, const char* _ethVersion);
static void stopping(std::string const& _clientImpl, const char* _ethVersion);
static void p2pConnected(
std::string const& _id,
bi::tcp::endpoint const& _addr,
std::chrono::system_clock::time_point const& _ts,
std::string const& _remoteVersion,
unsigned int _numConnections
);
static void p2pDisconnected(std::string const& _id, bi::tcp::endpoint const& _addr, unsigned int _numConnections);
static void minedNewBlock(
std::string const& _hash,
std::string const& _blockNumber,
std::string const& _chainHeadHash,
std::string const& _prevHash
);
static void chainReceivedNewBlock(
std::string const& _hash,
std::string const& _blockNumber,
std::string const& _chainHeadHash,
std::string const& _remoteID,
std::string const& _prevHash
);
static void chainNewHead(
std::string const& _hash,
std::string const& _blockNumber,
std::string const& _chainHeadHash,
std::string const& _prevHash
);
static void transactionReceived(std::string const& _hash, std::string const& _remoteId);
private:
// Singleton class. Private default ctor and no copying
StructuredLogger() = default;
StructuredLogger(StructuredLogger const&) = delete;
void operator=(StructuredLogger const&) = delete;
/// @returns a string representation of a timepoint
static std::string timePointToString(std::chrono::system_clock::time_point const& _ts);
void outputJson(Json::Value const& _value, std::string const& _name) const;
bool m_enabled = false;
std::string m_timeFormat = "%Y-%m-%dT%H:%M:%S";
};
}

46
libdevcore/UndefMacros.h

@ -0,0 +1,46 @@
/*
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 UndefMacros.h
* @author Lefteris <lefteris@ethdev.com>
* @date 2015
*
* This header should be used to #undef some really evil macros defined by
* windows.h which result in conflict with our libsolidity/Token.h
*/
#pragma once
#if defined(_MSC_VER) || defined(__MINGW32__)
#undef DELETE
#undef IN
#undef VOID
#undef THIS
#undef CONST
// Conflicting define on MinGW in windows.h
// windows.h(19): #define interface struct
#ifdef interface
#undef interface
#endif
#elif defined(DELETE) || defined(IN) || defined(VOID) || defined(THIS) || defined(CONST) || defined(interface)
#error "The preceding macros in this header file are reserved for V8's "\
"TOKEN_LIST. Please add a platform specific define above to undefine "\
"overlapping macros."
#endif

2
libdevcore/debugbreak.h

@ -27,7 +27,7 @@
#ifndef DEBUG_BREAK_H
#define DEBUG_BREAK_H
#ifdef _MSC_VER
#if defined(_MSC_VER) || defined(__MINGW32__)
#define debug_break __debugbreak

2
libdevcrypto/CMakeLists.txt

@ -28,6 +28,6 @@ target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

2
libethcore/CMakeLists.txt

@ -25,6 +25,6 @@ endif()
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

14
libethereum/BlockChain.cpp

@ -25,6 +25,7 @@
#include <test/JsonSpiritHeaders.h>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/StructuredLogger.h>
#include <libdevcrypto/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
@ -317,6 +318,13 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
}
#endif
StructuredLogger::chainReceivedNewBlock(
bi.headerHash(WithoutNonce).abridged(),
bi.nonce.abridged(),
currentHash().abridged(),
"", // TODO: remote id ??
bi.parentHash.abridged()
);
// cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children.";
h256s ret;
@ -331,6 +339,12 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
}
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(ret);
StructuredLogger::chainNewHead(
bi.headerHash(WithoutNonce).abridged(),
bi.nonce.abridged(),
currentHash().abridged(),
bi.parentHash.abridged()
);
}
else
{

2
libethereum/BlockChain.h

@ -96,7 +96,7 @@ public:
BlockInfo info(h256 _hash) const { return BlockInfo(block(_hash)); }
BlockInfo info() const { return BlockInfo(block()); }
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
/// Get the familiar details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 _hash) const { return queryExtras<BlockDetails, 0>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); }

7
libethereum/CMakeLists.txt

@ -13,6 +13,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE ethereum)
@ -35,6 +36,10 @@ target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} secp256k1)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
if (CMAKE_COMPILER_IS_MINGW)
target_link_libraries(${EXECUTABLE} ssp shlwapi)
endif()
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

36
libethereum/Client.cpp

@ -25,6 +25,7 @@
#include <thread>
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/StructuredLogger.h>
#include <libp2p/Host.h>
#include "Defaults.h"
#include "Executive.h"
@ -59,7 +60,7 @@ void VersionChecker::setOk()
}
}
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId, int miners):
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners):
Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
@ -69,8 +70,8 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean,
{
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (miners > -1)
setMiningThreads(miners);
if (_miners > -1)
setMiningThreads(_miners);
else
setMiningThreads();
if (_dbPath.size())
@ -291,7 +292,7 @@ LocalisedLogEntries Client::checkWatch(unsigned _watchId)
return ret;
}
void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed)
void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _sha3)
{
Guard l(m_filterLock);
for (pair<h256 const, InstalledFilter>& i: m_filters)
@ -303,7 +304,7 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& i
{
// filter catches them
for (LogEntry const& l: m)
i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1));
i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1, _sha3));
io_changed.insert(i.first);
}
}
@ -319,14 +320,16 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed)
for (pair<h256 const, InstalledFilter>& i: m_filters)
if ((unsigned)i.second.filter.latest() >= d.number && (unsigned)i.second.filter.earliest() <= d.number && i.second.filter.matches(d.logBloom))
// acceptable number & looks like block may contain a matching log entry.
for (TransactionReceipt const& tr: br.receipts)
for (size_t j = 0; j < br.receipts.size(); j++)
{
auto tr = br.receipts[j];
auto m = i.second.filter.matches(tr);
if (m.size())
{
auto sha3 = transaction(d.hash, j).sha3();
// filter catches them
for (LogEntry const& l: m)
i.second.changes.push_back(LocalisedLogEntry(l, (unsigned)d.number));
i.second.changes.push_back(LocalisedLogEntry(l, (unsigned)d.number, sha3));
io_changed.insert(i.first);
}
}
@ -415,6 +418,7 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _
}
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged());
cnote << "New transaction " << t;
m_tq.attemptImport(t.rlp());
}
@ -582,8 +586,9 @@ void Client::doWork()
TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq);
if (newPendingReceipts.size())
{
for (auto i: newPendingReceipts)
appendFromNewPending(i, changeds);
for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
changeds.insert(PendingChangedFilter);
if (isMining())
@ -756,6 +761,7 @@ LocalisedLogEntries Client::logs(LogFilter const& _f) const
{
// Might have a transaction that contains a matching log.
TransactionReceipt const& tr = m_postMine.receipt(i);
auto sha3 = m_postMine.pending()[i].sha3();
LogEntries le = _f.matches(tr);
if (le.size())
{
@ -763,7 +769,7 @@ LocalisedLogEntries Client::logs(LogFilter const& _f) const
if (s)
s--;
else
ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin));
ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, sha3));
}
}
begin = m_bc.number();
@ -782,11 +788,15 @@ LocalisedLogEntries Client::logs(LogFilter const& _f) const
int total = 0;
#endif
// check block bloom
if (_f.matches(m_bc.info(h).logBloom))
for (TransactionReceipt receipt: m_bc.receipts(h).receipts)
auto info = m_bc.info(h);
auto receipts = m_bc.receipts(h).receipts;
if (_f.matches(info.logBloom))
for (size_t i = 0; i < receipts.size(); i++)
{
TransactionReceipt receipt = receipts[i];
if (_f.matches(receipt.bloom()))
{
auto h = transaction(info.hash, i).sha3();
LogEntries le = _f.matches(receipt);
if (le.size())
{
@ -798,7 +808,7 @@ LocalisedLogEntries Client::logs(LogFilter const& _f) const
if (s)
s--;
else
ret.insert(ret.begin(), LocalisedLogEntry(le[j], n));
ret.insert(ret.begin(), LocalisedLogEntry(le[j], n, h));
}
}
}

15
libethereum/Client.h

@ -27,7 +27,9 @@
#include <atomic>
#include <string>
#include <array>
#include <boost/utility.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h>
@ -44,6 +46,7 @@
namespace dev
{
namespace eth
{
@ -166,7 +169,13 @@ class Client: public MinerHost, public Interface, Worker
public:
/// New-style Constructor.
explicit Client(p2p::Host* _host, std::string const& _dbPath = std::string(), bool _forceClean = false, u256 _networkId = 0, int miners = -1);
explicit Client(
p2p::Host* _host,
std::string const& _dbPath = std::string(),
bool _forceClean = false,
u256 _networkId = 0,
int _miners = -1
);
/// Destructor.
virtual ~Client();
@ -220,7 +229,7 @@ public:
/// @returns the length of the chain.
virtual unsigned number() const { return m_bc.number(); }
/// Get a map containing each of the pending transactions.
/// Get the list of pending transactions.
/// @TODO: Remove in favour of transactions().
virtual Transactions pending() const { return m_postMine.pending(); }
@ -311,7 +320,7 @@ public:
protected:
/// Collate the changed filters for the bloom filter of the given pending transaction.
/// Insert any filters that are activated into @a o_changed.
void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed);
void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _sha3);
/// Collate the changed filters for the hash of the given block.
/// Insert any filters that are activated into @a o_changed.

1
libethereum/EthereumHost.h

@ -28,6 +28,7 @@
#include <memory>
#include <utility>
#include <thread>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>

4
libethereum/EthereumPeer.h

@ -26,6 +26,10 @@
#include <set>
#include <memory>
#include <utility>
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcore/RangeMask.h>

1
libethereum/Miner.h

@ -32,6 +32,7 @@
namespace dev
{
namespace eth
{

7
libethereum/State.cpp

@ -27,6 +27,7 @@
#include <boost/timer.hpp>
#include <secp256k1/secp256k1.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/StructuredLogger.h>
#include <libevmcore/Instruction.h>
#include <libethcore/Exceptions.h>
#include <libevm/VMFactory.h>
@ -820,6 +821,12 @@ void State::completeMine()
ret.swapOut(m_currentBytes);
m_currentBlock.hash = sha3(RLP(m_currentBytes)[0].data());
cnote << "Mined " << m_currentBlock.hash.abridged() << "(parent: " << m_currentBlock.parentHash.abridged() << ")";
StructuredLogger::minedNewBlock(
m_currentBlock.hash.abridged(),
m_currentBlock.nonce.abridged(),
"", //TODO: chain head hash here ??
m_currentBlock.parentHash.abridged()
);
// Quickly reset the transactions.
// TODO: Leave this in a better state than this limbo, or at least record that it's in limbo.

2
libethereumx/CMakeLists.txt

@ -30,6 +30,6 @@ target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} secp256k1)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

2
libevm/CMakeLists.txt

@ -34,6 +34,6 @@ if (EVMJIT)
target_link_libraries(${EXECUTABLE} evmjit-cpp)
endif()
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

3
libevm/ExtVMFace.h

@ -63,9 +63,10 @@ using LogEntries = std::vector<LogEntry>;
struct LocalisedLogEntry: public LogEntry
{
LocalisedLogEntry() {}
LocalisedLogEntry(LogEntry const& _le, unsigned _number): LogEntry(_le), number(_number) {}
LocalisedLogEntry(LogEntry const& _le, unsigned _number, h256 _sha3 = {}): LogEntry(_le), number(_number), sha3(_sha3) {}
unsigned number = 0;
h256 sha3;
};
using LocalisedLogEntries = std::vector<LocalisedLogEntry>;

2
libevmcore/CMakeLists.txt

@ -26,6 +26,6 @@ endif()
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

2
libjsqrc/CMakeLists.txt

@ -22,4 +22,4 @@ if (ETH_NODE AND ETH_NPM)
add_dependencies(jsqrc ethereumjs)
endif()
install( TARGETS jsqrc ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS jsqrc RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )

9
libjsqrc/ethereumjs/README.md

@ -75,14 +75,13 @@ npm test
**Please note this repo is in it's early stage.**
If you'd like to run a WebSocket ethereum node check out
[go-ethereum](https://github.com/ethereum/go-ethereum).
If you'd like to run a Http ethereum node check out
[cpp-ethereum](https://github.com/ethereum/cpp-ethereum).
To install ethereum and spawn a node:
Install ethereum and spawn a node:
```
go get github.com/ethereum/go-ethereum/ethereum
ethereum -ws -loglevel=4
eth -j
```
[npm-image]: https://badge.fury.io/js/ethereum.js.png

2
libjsqrc/ethereumjs/bower.json

@ -1,7 +1,7 @@
{
"name": "ethereum.js",
"namespace": "ethereum",
"version": "0.0.15",
"version": "0.0.16",
"description": "Ethereum Compatible JavaScript API",
"main": [
"./dist/ethereum.js",

140
libjsqrc/ethereumjs/dist/ethereum.js

@ -22,7 +22,6 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ
* @date 2014
*/
var web3 = require('./web3');
var utils = require('./utils');
var types = require('./types');
var c = require('./const');
@ -41,11 +40,11 @@ var arrayType = function (type) {
var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return f.formatInputInt(value.length);
return f.formatInputInt(value.length);
return "";
};
var inputTypes = types.inputTypes();
var inputTypes = types.inputTypes();
/// Formats input params to bytes
/// @param abi contract method inputs
@ -53,13 +52,16 @@ var inputTypes = types.inputTypes();
/// @returns bytes representation of input params
var formatInput = function (inputs, params) {
var bytes = "";
var toAppendConstant = "";
var toAppendArrayContent = "";
/// first we iterate in search for dynamic
/// first we iterate in search for dynamic
inputs.forEach(function (input, index) {
bytes += dynamicTypeBytes(input.type, params[index]);
});
inputs.forEach(function (input, i) {
/*jshint maxcomplexity:5 */
var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
typeMatch = inputTypes[j].type(inputs[i].type, params[i]);
@ -69,17 +71,19 @@ var formatInput = function (inputs, params) {
}
var formatter = inputTypes[j - 1].format;
var toAppend = "";
if (arrayType(inputs[i].type))
toAppend = params[i].reduce(function (acc, curr) {
toAppendArrayContent += params[i].reduce(function (acc, curr) {
return acc + formatter(curr);
}, "");
else if (inputs[i].type === 'string')
toAppendArrayContent += formatter(params[i]);
else
toAppend = formatter(params[i]);
bytes += toAppend;
toAppendConstant += formatter(params[i]);
});
bytes += toAppendConstant + toAppendArrayContent;
return bytes;
};
@ -89,14 +93,14 @@ var dynamicBytesLength = function (type) {
return 0;
};
var outputTypes = types.outputTypes();
var outputTypes = types.outputTypes();
/// Formats output bytes back to param list
/// @param contract abi method outputs
/// @param bytes representtion of output
/// @returns array of output params
/// @param bytes representtion of output
/// @returns array of output params
var formatOutput = function (outs, output) {
output = output.slice(2);
var result = [];
var padding = c.ETH_PADDING * 2;
@ -104,7 +108,7 @@ var formatOutput = function (outs, output) {
var dynamicPartLength = outs.reduce(function (acc, curr) {
return acc + dynamicBytesLength(curr.type);
}, 0);
var dynamicPart = output.slice(0, dynamicPartLength);
output = output.slice(dynamicPartLength);
@ -125,13 +129,13 @@ var formatOutput = function (outs, output) {
dynamicPart = dynamicPart.slice(padding);
var array = [];
for (var k = 0; k < size; k++) {
array.push(formatter(output.slice(0, padding)));
array.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
}
result.push(array);
}
else if (types.prefixedType('string')(outs[i].type)) {
dynamicPart = dynamicPart.slice(padding);
dynamicPart = dynamicPart.slice(padding);
result.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
} else {
@ -149,14 +153,14 @@ var formatOutput = function (outs, output) {
var inputParser = function (json) {
var parser = {};
json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function () {
var params = Array.prototype.slice.call(arguments);
return formatInput(method.inputs, params);
};
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
@ -173,7 +177,7 @@ var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function (output) {
@ -190,27 +194,14 @@ var outputParser = function (json) {
return parser;
};
/// @param function/event name for which we want to get signature
/// @returns signature of function/event with given name
var signatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);
};
var eventSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name));
};
module.exports = {
inputParser: inputParser,
outputParser: outputParser,
formatInput: formatInput,
formatOutput: formatOutput,
signatureFromAscii: signatureFromAscii,
eventSignatureFromAscii: eventSignatureFromAscii
formatOutput: formatOutput
};
},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(require,module,exports){
},{"./const":2,"./formatters":8,"./types":15,"./utils":16}],2:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -296,6 +287,7 @@ var web3 = require('./web3');
var abi = require('./abi');
var utils = require('./utils');
var eventImpl = require('./event');
var signature = require('./signature');
var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js
@ -343,12 +335,12 @@ var addFunctionsToContract = function (contract, desc, address) {
var impl = function () {
/*jshint maxcomplexity:7 */
var params = Array.prototype.slice.call(arguments);
var signature = abi.signatureFromAscii(method.name);
var sign = signature.functionSignatureFromAscii(method.name);
var parsed = inputParser[displayName][typeName].apply(null, params);
var options = contract._options || {};
options.to = address;
options.data = signature + parsed;
options.data = sign + parsed;
var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);
var collapse = options.collapse !== false;
@ -402,7 +394,7 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) {
Object.defineProperty(contract, 'topic', {
get: function() {
return utils.filterEvents(desc).map(function (e) {
return abi.eventSignatureFromAscii(e.name);
return signature.eventSignatureFromAscii(e.name);
});
}
});
@ -415,8 +407,8 @@ var addEventsToContract = function (contract, desc, address) {
var impl = function () {
var params = Array.prototype.slice.call(arguments);
var signature = abi.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, signature, e);
var sign = signature.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, sign, e);
var o = event.apply(null, params);
var outputFormatter = function (data) {
var parser = eventImpl.outputParser(e);
@ -489,7 +481,7 @@ var contract = function (address, desc) {
module.exports = contract;
},{"./abi":1,"./event":6,"./utils":15,"./web3":17}],4:[function(require,module,exports){
},{"./abi":1,"./event":6,"./signature":14,"./utils":16,"./web3":18}],4:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -638,6 +630,7 @@ module.exports = {
var abi = require('./abi');
var utils = require('./utils');
var signature = require('./signature');
/// filter inputs array && returns only indexed (or not) inputs
/// @param inputs array
@ -676,14 +669,14 @@ var indexedParamsToTopics = function (event, indexed) {
});
};
var inputParser = function (address, signature, event) {
var inputParser = function (address, sign, event) {
// valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'
return function (indexed, options) {
var o = options || {};
o.address = address;
o.topic = [];
o.topic.push(signature);
o.topic.push(sign);
if (indexed) {
o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));
}
@ -712,6 +705,7 @@ var outputParser = function (event) {
var result = {
event: utils.extractDisplayName(event.name),
number: output.number,
hash: output.hash,
args: {}
};
@ -735,8 +729,8 @@ var outputParser = function (event) {
var getMatchingEvent = function (events, payload) {
for (var i = 0; i < events.length; i++) {
var signature = abi.eventSignatureFromAscii(events[i].name);
if (signature === payload.topic[0]) {
var sign = signature.eventSignatureFromAscii(events[i].name);
if (sign === payload.topic[0]) {
return events[i];
}
}
@ -751,7 +745,7 @@ module.exports = {
};
},{"./abi":1,"./utils":15}],7:[function(require,module,exports){
},{"./abi":1,"./signature":14,"./utils":16}],7:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1023,7 +1017,7 @@ module.exports = {
};
},{"./const":2,"./utils":15}],9:[function(require,module,exports){
},{"./const":2,"./utils":16}],9:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1345,6 +1339,50 @@ module.exports = {
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file signature.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var web3 = require('./web3');
var c = require('./const');
/// @param function name for which we want to get signature
/// @returns signature of function with given name
var functionSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);
};
/// @param event name for which we want to get signature
/// @returns signature of event with given name
var eventSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name));
};
module.exports = {
functionSignatureFromAscii: functionSignatureFromAscii,
eventSignatureFromAscii: eventSignatureFromAscii
};
},{"./const":2,"./web3":18}],15:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file types.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
@ -1409,7 +1447,7 @@ module.exports = {
};
},{"./formatters":8}],15:[function(require,module,exports){
},{"./formatters":8}],16:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1554,7 +1592,7 @@ module.exports = {
};
},{"./const":2}],16:[function(require,module,exports){
},{"./const":2}],17:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1605,7 +1643,7 @@ module.exports = {
};
},{}],17:[function(require,module,exports){
},{}],18:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1796,7 +1834,7 @@ setupMethods(shhWatch, watches.shh());
module.exports = web3;
},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],"web3":[function(require,module,exports){
},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":16,"./watches":17}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3');
web3.providers.HttpSyncProvider = require('./lib/httpsync');
web3.providers.QtSyncProvider = require('./lib/qtsync');
@ -1805,7 +1843,7 @@ web3.abi = require('./lib/abi');
module.exports = web3;
},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"])
},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":18}]},{},["web3"])
//# sourceMappingURL=ethereum.js.map

10
libjsqrc/ethereumjs/dist/ethereum.js.map

File diff suppressed because one or more lines are too long

2
libjsqrc/ethereumjs/dist/ethereum.min.js

File diff suppressed because one or more lines are too long

57
libjsqrc/ethereumjs/lib/abi.js

@ -21,7 +21,6 @@
* @date 2014
*/
var web3 = require('./web3');
var utils = require('./utils');
var types = require('./types');
var c = require('./const');
@ -40,11 +39,11 @@ var arrayType = function (type) {
var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return f.formatInputInt(value.length);
return f.formatInputInt(value.length);
return "";
};
var inputTypes = types.inputTypes();
var inputTypes = types.inputTypes();
/// Formats input params to bytes
/// @param abi contract method inputs
@ -52,13 +51,16 @@ var inputTypes = types.inputTypes();
/// @returns bytes representation of input params
var formatInput = function (inputs, params) {
var bytes = "";
var toAppendConstant = "";
var toAppendArrayContent = "";
/// first we iterate in search for dynamic
/// first we iterate in search for dynamic
inputs.forEach(function (input, index) {
bytes += dynamicTypeBytes(input.type, params[index]);
});
inputs.forEach(function (input, i) {
/*jshint maxcomplexity:5 */
var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
typeMatch = inputTypes[j].type(inputs[i].type, params[i]);
@ -68,17 +70,19 @@ var formatInput = function (inputs, params) {
}
var formatter = inputTypes[j - 1].format;
var toAppend = "";
if (arrayType(inputs[i].type))
toAppend = params[i].reduce(function (acc, curr) {
toAppendArrayContent += params[i].reduce(function (acc, curr) {
return acc + formatter(curr);
}, "");
else if (inputs[i].type === 'string')
toAppendArrayContent += formatter(params[i]);
else
toAppend = formatter(params[i]);
bytes += toAppend;
toAppendConstant += formatter(params[i]);
});
bytes += toAppendConstant + toAppendArrayContent;
return bytes;
};
@ -88,14 +92,14 @@ var dynamicBytesLength = function (type) {
return 0;
};
var outputTypes = types.outputTypes();
var outputTypes = types.outputTypes();
/// Formats output bytes back to param list
/// @param contract abi method outputs
/// @param bytes representtion of output
/// @returns array of output params
/// @param bytes representtion of output
/// @returns array of output params
var formatOutput = function (outs, output) {
output = output.slice(2);
var result = [];
var padding = c.ETH_PADDING * 2;
@ -103,7 +107,7 @@ var formatOutput = function (outs, output) {
var dynamicPartLength = outs.reduce(function (acc, curr) {
return acc + dynamicBytesLength(curr.type);
}, 0);
var dynamicPart = output.slice(0, dynamicPartLength);
output = output.slice(dynamicPartLength);
@ -124,13 +128,13 @@ var formatOutput = function (outs, output) {
dynamicPart = dynamicPart.slice(padding);
var array = [];
for (var k = 0; k < size; k++) {
array.push(formatter(output.slice(0, padding)));
array.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
}
result.push(array);
}
else if (types.prefixedType('string')(outs[i].type)) {
dynamicPart = dynamicPart.slice(padding);
dynamicPart = dynamicPart.slice(padding);
result.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
} else {
@ -148,14 +152,14 @@ var formatOutput = function (outs, output) {
var inputParser = function (json) {
var parser = {};
json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function () {
var params = Array.prototype.slice.call(arguments);
return formatInput(method.inputs, params);
};
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
@ -172,7 +176,7 @@ var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function (output) {
@ -189,22 +193,9 @@ var outputParser = function (json) {
return parser;
};
/// @param function/event name for which we want to get signature
/// @returns signature of function/event with given name
var signatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);
};
var eventSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name));
};
module.exports = {
inputParser: inputParser,
outputParser: outputParser,
formatInput: formatInput,
formatOutput: formatOutput,
signatureFromAscii: signatureFromAscii,
eventSignatureFromAscii: eventSignatureFromAscii
formatOutput: formatOutput
};

11
libjsqrc/ethereumjs/lib/contract.js

@ -24,6 +24,7 @@ var web3 = require('./web3');
var abi = require('./abi');
var utils = require('./utils');
var eventImpl = require('./event');
var signature = require('./signature');
var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js
@ -71,12 +72,12 @@ var addFunctionsToContract = function (contract, desc, address) {
var impl = function () {
/*jshint maxcomplexity:7 */
var params = Array.prototype.slice.call(arguments);
var signature = abi.signatureFromAscii(method.name);
var sign = signature.functionSignatureFromAscii(method.name);
var parsed = inputParser[displayName][typeName].apply(null, params);
var options = contract._options || {};
options.to = address;
options.data = signature + parsed;
options.data = sign + parsed;
var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);
var collapse = options.collapse !== false;
@ -130,7 +131,7 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) {
Object.defineProperty(contract, 'topic', {
get: function() {
return utils.filterEvents(desc).map(function (e) {
return abi.eventSignatureFromAscii(e.name);
return signature.eventSignatureFromAscii(e.name);
});
}
});
@ -143,8 +144,8 @@ var addEventsToContract = function (contract, desc, address) {
var impl = function () {
var params = Array.prototype.slice.call(arguments);
var signature = abi.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, signature, e);
var sign = signature.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, sign, e);
var o = event.apply(null, params);
var outputFormatter = function (data) {
var parser = eventImpl.outputParser(e);

10
libjsqrc/ethereumjs/lib/event.js

@ -22,6 +22,7 @@
var abi = require('./abi');
var utils = require('./utils');
var signature = require('./signature');
/// filter inputs array && returns only indexed (or not) inputs
/// @param inputs array
@ -60,14 +61,14 @@ var indexedParamsToTopics = function (event, indexed) {
});
};
var inputParser = function (address, signature, event) {
var inputParser = function (address, sign, event) {
// valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'
return function (indexed, options) {
var o = options || {};
o.address = address;
o.topic = [];
o.topic.push(signature);
o.topic.push(sign);
if (indexed) {
o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));
}
@ -96,6 +97,7 @@ var outputParser = function (event) {
var result = {
event: utils.extractDisplayName(event.name),
number: output.number,
hash: output.hash,
args: {}
};
@ -119,8 +121,8 @@ var outputParser = function (event) {
var getMatchingEvent = function (events, payload) {
for (var i = 0; i < events.length; i++) {
var signature = abi.eventSignatureFromAscii(events[i].name);
if (signature === payload.topic[0]) {
var sign = signature.eventSignatureFromAscii(events[i].name);
if (sign === payload.topic[0]) {
return events[i];
}
}

42
libjsqrc/ethereumjs/lib/signature.js

@ -0,0 +1,42 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file signature.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var web3 = require('./web3');
var c = require('./const');
/// @param function name for which we want to get signature
/// @returns signature of function with given name
var functionSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);
};
/// @param event name for which we want to get signature
/// @returns signature of event with given name
var eventSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name));
};
module.exports = {
functionSignatureFromAscii: functionSignatureFromAscii,
eventSignatureFromAscii: eventSignatureFromAscii
};

2
libjsqrc/ethereumjs/package.json

@ -1,7 +1,7 @@
{
"name": "ethereum.js",
"namespace": "ethereum",
"version": "0.0.15",
"version": "0.0.16",
"description": "Ethereum Compatible JavaScript API",
"main": "./index.js",
"directories": {

203
libjsqrc/ethereumjs/test/abi.inputParser.js

@ -29,7 +29,7 @@ describe('abi', function() {
d[0].inputs = [
{ type: "uint" }
];
// when
var parser = abi.inputParser(d);
@ -37,7 +37,7 @@ describe('abi', function() {
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
@ -67,7 +67,7 @@ describe('abi', function() {
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
@ -80,7 +80,7 @@ describe('abi', function() {
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input uint256', function() {
// given
@ -97,7 +97,7 @@ describe('abi', function() {
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
@ -108,7 +108,7 @@ describe('abi', function() {
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input int', function() {
@ -119,7 +119,7 @@ describe('abi', function() {
d[0].inputs = [
{ type: "int" }
];
// when
var parser = abi.inputParser(d);
@ -130,7 +130,7 @@ describe('abi', function() {
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
@ -162,7 +162,7 @@ describe('abi', function() {
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
@ -177,7 +177,7 @@ describe('abi', function() {
});
it('should parse input int256', function() {
// given
var d = clone(description);
@ -195,7 +195,7 @@ describe('abi', function() {
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
@ -206,11 +206,11 @@ describe('abi', function() {
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input bool', function() {
// given
var d = clone(description);
@ -235,14 +235,14 @@ describe('abi', function() {
d[0].inputs = [
{ type: "hash" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
});
});
it('should parse input hash256', function() {
@ -272,7 +272,7 @@ describe('abi', function() {
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
});
@ -285,17 +285,17 @@ describe('abi', function() {
d[0].inputs = [
{ type: "address" }
];
// when
var parser = abi.inputParser(d)
// then
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
});
it('should parse input string', function () {
// given
var d = clone(description);
@ -308,8 +308,9 @@ describe('abi', function() {
// then
assert.equal(
parser.test('hello'),
"000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"
parser.test('hello'),
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000"
);
assert.equal(
parser.test('world'),
@ -317,8 +318,52 @@ describe('abi', function() {
);
});
it('should parse input int followed by a string', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int" },
{ type: "string" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test(9, 'hello'),
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000009" +
"68656c6c6f000000000000000000000000000000000000000000000000000000"
);
});
it('should parse input string followed by an int', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "string" },
{ type: "int" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test('hello', 9),
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000009" +
"68656c6c6f000000000000000000000000000000000000000000000000000000"
);
});
it('should use proper method name', function () {
// given
var d = clone(description);
d[0].name = 'helloworld(int)';
@ -334,9 +379,9 @@ describe('abi', function() {
assert.equal(parser.helloworld['int'](1), "0000000000000000000000000000000000000000000000000000000000000001");
});
it('should parse multiple methods', function () {
// given
var d = [{
name: "test",
@ -356,14 +401,14 @@ describe('abi', function() {
//then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(
parser.test2('hello'),
parser.test2('hello'),
"000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"
);
});
it('should parse input array of ints', function () {
// given
var d = clone(description);
@ -377,14 +422,91 @@ describe('abi', function() {
// then
assert.equal(
parser.test([5, 6]),
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006"
);
});
it('should parse an array followed by an int', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int[]" },
{ type: "int" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test([5, 6], 3),
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000003" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006"
);
});
it('should parse an int followed by an array', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int" },
{ type: "int[]" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test(3, [5, 6]),
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000003" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006"
);
});
it('should parse mixture of arrays and ints', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int" },
{ type: "int[]" },
{ type: "int" },
{ type: "int[]" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test(3, [5, 6, 1, 2], 7, [8, 9]),
"0000000000000000000000000000000000000000000000000000000000000004" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000003" +
"0000000000000000000000000000000000000000000000000000000000000007" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006" +
"0000000000000000000000000000000000000000000000000000000000000001" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000008" +
"0000000000000000000000000000000000000000000000000000000000000009"
);
});
it('should parse input real', function () {
// given
var d = clone(description);
@ -396,15 +518,15 @@ describe('abi', function() {
var parser = abi.inputParser(d);
// then
assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000");
assert.equal(parser.test([-1]), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000");
assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000");
assert.equal(parser.test([-1]), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000");
});
it('should parse input ureal', function () {
// given
var d = clone(description);
@ -416,12 +538,11 @@ describe('abi', function() {
var parser = abi.inputParser(d);
// then
assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000");
assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000");
});
});
});

2
liblll/CMakeLists.txt

@ -27,6 +27,6 @@ endif()
target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

3
libnatspec/CMakeLists.txt

@ -14,6 +14,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE natspec)
@ -31,5 +32,5 @@ target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Qml)
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

7
libp2p/CMakeLists.txt

@ -15,6 +15,7 @@ include_directories(BEFORE ..)
# we may not use it in libp2p, but one of our dependecies is including leveldb in header file
# and windows is failing to build without that
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
if (MINIUPNPC_FOUND)
include_directories(${MINIUPNPC_INCLUDE_DIRS})
@ -37,6 +38,10 @@ endif()
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
if (CMAKE_COMPILER_IS_MINGW)
target_link_libraries(${EXECUTABLE} ws2_32 mswsock)
endif()
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

3
libp2p/Common.h

@ -27,8 +27,11 @@
#include <string>
#include <set>
#include <vector>
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <chrono>
#include <libdevcrypto/Common.h>
#include <libdevcore/Log.h>

113
libp2p/Host.cpp

@ -24,9 +24,12 @@
#include <chrono>
#include <thread>
#include <mutex>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h>
#include <libdevcrypto/FileSystem.h>
#include "Session.h"
@ -59,7 +62,7 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, byte
for (auto address: m_ifAddresses)
if (address.is_v4())
clog(NetNote) << "IP Address: " << address << " = " << (isPrivateAddress(address) ? "[LOCAL]" : "[PEER]");
clog(NetNote) << "Id:" << id();
}
@ -88,11 +91,11 @@ void Host::stop()
return;
m_run = false;
}
// wait for m_timer to reset (indicating network scheduler has stopped)
while (!!m_timer)
this_thread::sleep_for(chrono::milliseconds(50));
// stop worker thread
stopWorking();
}
@ -101,12 +104,12 @@ void Host::doneWorking()
{
// reset ioservice (allows manually polling network, below)
m_ioService.reset();
// shutdown acceptor
m_tcp4Acceptor.cancel();
if (m_tcp4Acceptor.is_open())
m_tcp4Acceptor.close();
// There maybe an incoming connection which started but hasn't finished.
// Wait for acceptor to end itself instead of assuming it's complete.
// This helps ensure a peer isn't stopped at the same time it's starting
@ -133,17 +136,17 @@ void Host::doneWorking()
}
if (!n)
break;
// poll so that peers send out disconnect packets
m_ioService.poll();
}
// stop network (again; helpful to call before subsequent reset())
m_ioService.stop();
// reset network (allows reusing ioservice in future)
m_ioService.reset();
// finally, clear out peers (in case they're lingering)
RecursiveGuard l(x_sessions);
m_sessions.clear();
@ -158,6 +161,13 @@ void Host::registerPeer(std::shared_ptr<Session> _s, CapDescs const& _caps)
{
{
clog(NetNote) << "p2p.host.peer.register" << _s->m_peer->id.abridged();
StructuredLogger::p2pConnected(
_s->m_peer->id.abridged(),
_s->m_peer->peerEndpoint(),
_s->m_peer->m_lastConnected,
_s->m_info.clientVersion,
peerCount()
);
RecursiveGuard l(x_sessions);
// TODO: temporary loose-coupling; if m_peers already has peer,
// it is same as _s->m_peer. (fixing next PR)
@ -165,7 +175,7 @@ void Host::registerPeer(std::shared_ptr<Session> _s, CapDescs const& _caps)
m_peers[_s->m_peer->id] = _s->m_peer;
m_sessions[_s->m_peer->id] = _s;
}
unsigned o = (unsigned)UserPacket;
for (auto const& i: _caps)
if (haveCapability(i))
@ -181,7 +191,7 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
if (_e == NodeEntryAdded)
{
clog(NetNote) << "p2p.host.nodeTable.events.nodeEntryAdded " << _n;
auto n = m_nodeTable->node(_n);
if (n)
{
@ -198,12 +208,12 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
p->endpoint = NodeIPEndpoint(n.endpoint.udp, n.endpoint.tcp);
p->required = n.required;
m_peers[_n] = p;
clog(NetNote) << "p2p.host.peers.events.peersAdded " << _n << p->endpoint.tcp.address() << p->endpoint.udp.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
@ -219,7 +229,7 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
else if (_e == NodeEntryRemoved)
{
clog(NetNote) << "p2p.host.nodeTable.events.nodeEntryRemoved " << _n;
RecursiveGuard l(x_sessions);
m_peers.erase(_n);
}
@ -241,7 +251,7 @@ void Host::seal(bytes& _b)
void Host::determinePublic(string const& _publicAddress, bool _upnp)
{
m_peerAddresses.clear();
// no point continuing if there are no interface addresses or valid listen port
if (!m_ifAddresses.size() || m_listenPort < 1)
return;
@ -250,7 +260,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
for (auto addr: m_ifAddresses)
if ((m_netPrefs.localNetworking || !isPrivateAddress(addr)) && !isLocalHostAddress(addr))
m_peerAddresses.insert(addr);
// if user supplied address is a public address then we use it
// if user supplied address is private, and localnetworking is enabled, we use it
bi::address reqPublicAddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress)));
@ -264,7 +274,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
m_tcpPublic = reqPublic;
return;
}
// if address wasn't provided, then use first public ipv4 address found
for (auto addr: m_peerAddresses)
if (addr.is_v4() && !isPrivateAddress(addr))
@ -272,7 +282,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
m_tcpPublic = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort);
return;
}
// or find address via upnp
if (_upnp)
{
@ -296,7 +306,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
m_tcpPublic = bi::tcp::endpoint(addr, m_listenPort);
return;
}
// otherwise address is unspecified
m_tcpPublic = bi::tcp::endpoint(bi::address(), m_listenPort);
}
@ -304,7 +314,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
void Host::runAcceptor()
{
assert(m_listenPort > 0);
if (m_run && !m_accepting)
{
clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_tcpPublic << ")";
@ -325,7 +335,7 @@ void Host::runAcceptor()
// It's possible for an accepted connection to return an error in which
// case the socket may be open and must be closed to prevent asio from
// processing socket events after socket is deallocated.
bi::tcp::socket *s = new bi::tcp::socket(m_ioService);
m_tcp4Acceptor.async_accept(*s, [=](boost::system::error_code ec)
{
@ -349,7 +359,7 @@ void Host::runAcceptor()
clog(NetWarn) << "ERROR: " << _e.what();
}
}
// asio doesn't close socket on error
if (!success && s->is_open())
{
@ -360,7 +370,7 @@ void Host::runAcceptor()
m_accepting = false;
delete s;
if (ec.value() < 1)
runAcceptor();
});
@ -376,7 +386,7 @@ void Host::doHandshake(bi::tcp::socket* _socket, NodeId _nodeId)
shared_ptr<Peer> p;
if (_nodeId)
p = m_peers[_nodeId];
if (!p)
p.reset(new Peer());
p->endpoint.tcp.address(_socket->remote_endpoint().address());
@ -399,16 +409,16 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short
this_thread::sleep_for(chrono::milliseconds(50));
if (!m_run)
return;
if (_tcpPeerPort < 30300 || _tcpPeerPort > 30305)
cwarn << "Non-standard port being recorded: " << _tcpPeerPort;
if (_tcpPeerPort >= /*49152*/32768)
{
cwarn << "Private port being recorded - setting to 0";
_tcpPeerPort = 0;
}
boost::system::error_code ec;
bi::address addr = bi::address::from_string(_addr, ec);
if (ec)
@ -435,20 +445,20 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
this_thread::sleep_for(chrono::milliseconds(50));
if (!m_run)
return;
if (havePeerSession(_p->id))
{
clog(NetWarn) << "Aborted connect. Node already connected.";
return;
}
if (!m_nodeTable->haveNode(_p->id))
{
clog(NetWarn) << "Aborted connect. Node not in node table.";
m_nodeTable->addNode(*_p.get());
return;
}
// prevent concurrently connecting to a node
Peer *nptr = _p.get();
{
@ -457,7 +467,7 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
return;
m_pendingPeerConns.insert(nptr);
}
clog(NetConnect) << "Attempting connection to node" << _p->id.abridged() << "@" << _p->peerEndpoint() << "from" << id().abridged();
bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
s->async_connect(_p->peerEndpoint(), [=](boost::system::error_code const& ec)
@ -474,9 +484,10 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
_p->m_lastDisconnect = NoDisconnect;
_p->m_lastConnected = std::chrono::system_clock::now();
_p->m_failedAttempts = 0;
auto ps = make_shared<Session>(this, std::move(*s), _p);
ps->start();
}
delete s;
Guard l(x_pendingNodeConns);
@ -515,22 +526,22 @@ void Host::run(boost::system::error_code const&)
{
// reset NodeTable
m_nodeTable.reset();
// stopping io service allows running manual network operations for shutdown
// and also stops blocking worker thread, allowing worker thread to exit
m_ioService.stop();
// resetting timer signals network that nothing else can be scheduled to run
m_timer.reset();
return;
}
m_nodeTable->processEvents();
for (auto p: m_sessions)
if (auto pp = p.second.lock())
pp->serviceNodesRequest();
keepAlivePeers();
disconnectLatePeers();
@ -544,15 +555,15 @@ void Host::run(boost::system::error_code const&)
connect(p.second);
break;
}
if (c < m_idealPeerCount)
m_nodeTable->discover();
auto runcb = [this](boost::system::error_code const& error) { run(error); };
m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval));
m_timer->async_wait(runcb);
}
void Host::startedWorking()
{
asserts(!m_timer);
@ -566,33 +577,33 @@ void Host::startedWorking()
m_timer.reset(new boost::asio::deadline_timer(m_ioService));
m_run = true;
}
// try to open acceptor (todo: ipv6)
m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs.listenPort);
// start capability threads
for (auto const& h: m_capabilities)
h.second->onStarting();
// determine public IP, but only if we're able to listen for connections
// todo: GUI when listen is unavailable in UI
if (m_listenPort)
{
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
if (m_listenPort > 0)
runAcceptor();
}
else
clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "Listen port is invalid or unavailable. Node Table using default port (30303).";
// TODO: add m_tcpPublic endpoint; sort out endpoint stuff for nodetable
m_nodeTable.reset(new NodeTable(m_ioService, m_alias, m_listenPort > 0 ? m_listenPort : 30303));
m_nodeTable->setEventHandler(new HostNodeTableHandler(*this));
restoreNetwork(&m_restoreNetwork);
clog(NetNote) << "p2p.started id:" << id().abridged();
run(boost::system::error_code());
}
@ -606,7 +617,7 @@ void Host::keepAlivePeers()
{
if (chrono::steady_clock::now() - c_keepAliveInterval < m_lastPing)
return;
RecursiveGuard l(x_sessions);
for (auto p: m_sessions)
if (auto pp = p.second.lock())
@ -641,7 +652,7 @@ bytes Host::saveNetwork() const
peers.push_back(*p.second);
}
peers.sort();
RLPStream network;
int count = 0;
{
@ -683,7 +694,7 @@ bytes Host::saveNetwork() const
count++;
}
}
RLPStream ret(3);
ret << 1 << m_alias.secret();
ret.appendList(count).appendRaw(network.out(), count);
@ -695,7 +706,7 @@ void Host::restoreNetwork(bytesConstRef _b)
// nodes can only be added if network is added
if (!isStarted())
BOOST_THROW_EXCEPTION(NetworkStartRequired());
RecursiveGuard l(x_sessions);
RLP r(_b);
if (r.itemCount() > 0 && r[0].isInt() && r[0].toInt<int>() == 1)

66
libp2p/Host.h

@ -30,6 +30,7 @@
#include <utility>
#include <thread>
#include <chrono>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
@ -56,7 +57,7 @@ public:
HostNodeTableHandler(Host& _host);
Host const& host() const { return m_host; }
private:
virtual void processEvent(NodeId const& _n, NodeTableEventType const& _e);
@ -82,23 +83,27 @@ class Host: public Worker
friend class HostNodeTableHandler;
friend class Session;
friend class HostCapabilityFace;
public:
/// Start server, listening for connections on the given port.
Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bytesConstRef _restoreNetwork = bytesConstRef());
Host(
std::string const& _clientVersion,
NetworkPreferences const& _n = NetworkPreferences(),
bytesConstRef _restoreNetwork = bytesConstRef()
);
/// Will block on network process events.
virtual ~Host();
/// Interval at which Host::run will call keepAlivePeers to ping peers.
std::chrono::seconds const c_keepAliveInterval = std::chrono::seconds(30);
/// Disconnect timeout after failure to respond to keepAlivePeers ping.
std::chrono::milliseconds const c_keepAliveTimeOut = std::chrono::milliseconds(1000);
/// Default host for current version of client.
static std::string pocHost();
/// Basic peer network protocol version.
unsigned protocolVersion() const;
@ -108,23 +113,23 @@ public:
bool haveCapability(CapDesc const& _name) const { return m_capabilities.count(_name) != 0; }
CapDescs caps() const { CapDescs ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; }
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; } }
bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; }
void addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPort, unsigned short _udpPort);
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
/// Get peer information.
PeerSessionInfos peerSessionInfo() const;
/// Get number of peers connected.
size_t peerCount() const;
/// Get the address we're listening on currently.
std::string listenAddress() const { return m_tcpPublic.address().to_string(); }
/// Get the port we're listening on currently.
unsigned short listenPort() const { return m_tcpPublic.port(); }
@ -138,11 +143,11 @@ public:
/// Start network. @threadsafe
void start();
/// Stop network. @threadsafe
/// Resets acceptor, socket, and IO service. Called by deallocator.
void stop();
/// @returns if network is running.
bool isStarted() const { return m_run; }
@ -155,25 +160,25 @@ protected:
/// Deserialise the data and populate the set of known peers.
void restoreNetwork(bytesConstRef _b);
private:
/// Populate m_peerAddresses with available public addresses.
void determinePublic(std::string const& _publicAddress, bool _upnp);
void connect(std::shared_ptr<Peer> const& _p);
/// Ping the peers to update the latency information and disconnect peers which have timed out.
void keepAlivePeers();
/// Disconnect peers which didn't respond to keepAlivePeers ping prior to c_keepAliveTimeOut.
void disconnectLatePeers();
/// Called only from startedWorking().
void runAcceptor();
/// Handler for verifying handshake siganture before creating session. _nodeId is passed for outbound connections. If successful, socket is moved to Session via std::move.
void doHandshake(bi::tcp::socket* _socket, NodeId _nodeId = NodeId());
void seal(bytes& _b);
/// Called by Worker. Not thread-safe; to be called only by worker.
@ -183,7 +188,7 @@ private:
/// Run network. Not thread-safe; to be called only by worker.
virtual void doWork();
/// Shutdown network. Not thread-safe; to be called only by worker.
virtual void doneWorking();
@ -191,14 +196,14 @@ private:
static KeyPair networkAlias(bytesConstRef _b);
bytes m_restoreNetwork; ///< Set by constructor and used to set Host key and restore network peers & nodes.
bool m_run = false; ///< Whether network is running.
std::mutex x_runTimer; ///< Start/stop mutex.
std::string m_clientVersion; ///< Our version string.
NetworkPreferences m_netPrefs; ///< Network settings.
/// Interface addresses (private, public)
std::vector<bi::address> m_ifAddresses; ///< Interface addresses.
@ -206,10 +211,10 @@ private:
ba::io_service m_ioService; ///< IOService for network stuff.
bi::tcp::acceptor m_tcp4Acceptor; ///< Listening acceptor.
std::unique_ptr<boost::asio::deadline_timer> m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms.
static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected.
std::set<Peer*> m_pendingPeerConns; /// Used only by connect(Peer&) to limit concurrently connecting to same node. See connect(shared_ptr<Peer>const&).
Mutex x_pendingNodeConns;
@ -219,22 +224,21 @@ private:
/// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer;
std::map<NodeId, std::shared_ptr<Peer>> m_peers;
/// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run())
/// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
mutable std::map<NodeId, std::weak_ptr<Session>> m_sessions;
mutable RecursiveMutex x_sessions;
unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to.
std::set<bi::address> m_peerAddresses; ///< Public addresses that peers (can) know us by.
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support.
std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
bool m_accepting = false;
};
}
}

27
libp2p/Network.cpp

@ -27,6 +27,7 @@
#endif
#include <boost/algorithm/string.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libethcore/Exceptions.h>
@ -46,7 +47,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
WSAData wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
BOOST_THROW_EXCEPTION(NoNetworking());
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
@ -54,7 +55,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
WSACleanup();
BOOST_THROW_EXCEPTION(NoNetworking());
}
struct hostent* phe = gethostbyname(ac);
if (phe == 0)
{
@ -62,7 +63,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
WSACleanup();
BOOST_THROW_EXCEPTION(NoNetworking());
}
for (int i = 0; phe->h_addr_list[i] != 0; ++i)
{
struct in_addr addr;
@ -72,18 +73,18 @@ std::vector<bi::address> Network::getInterfaceAddresses()
if (!isLocalHostAddress(address))
addresses.push_back(address.to_v4());
}
WSACleanup();
#else
ifaddrs* ifaddr;
if (getifaddrs(&ifaddr) == -1)
BOOST_THROW_EXCEPTION(NoNetworking());
for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (!ifa->ifa_addr || string(ifa->ifa_name) == "lo0")
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
@ -102,12 +103,12 @@ std::vector<bi::address> Network::getInterfaceAddresses()
addresses.push_back(address);
}
}
if (ifaddr!=NULL)
freeifaddrs(ifaddr);
#endif
return std::move(addresses);
}
@ -134,7 +135,7 @@ int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort
// both attempts failed
cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information();
}
// first attempt failed
_acceptor.close();
continue;
@ -146,7 +147,7 @@ int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort
bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr)
{
asserts(_listenPort != 0);
UPnP* upnp = nullptr;
try
{
@ -154,7 +155,7 @@ bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddres
}
// let m_upnp continue as null - we handle it properly.
catch (NoUPnPDevice) {}
bi::tcp::endpoint upnpep;
if (upnp && upnp->isValid())
{
@ -178,7 +179,7 @@ bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddres
}
else
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place).";
if (upnp)
delete upnp;
}

96
libp2p/NodeTable.h

@ -1,16 +1,16 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
@ -23,7 +23,9 @@
#include <algorithm>
#include <deque>
#include <boost/integer/static_log2.hpp>
#include <libp2p/UDP.h>
#include "Common.h"
@ -54,7 +56,7 @@ class NodeTableEventHandler
friend class NodeTable;
public:
virtual void processEvent(NodeId const& _n, NodeTableEventType const& _e) = 0;
protected:
/// Called by NodeTable on behalf of an implementation (Host) to process new events without blocking nodetable.
void processEvents()
@ -73,10 +75,10 @@ protected:
for (auto const& e: events)
processEvent(e.first, e.second);
}
/// Called by NodeTable to append event.
virtual void appendEvent(NodeId _n, NodeTableEventType _e) { Guard l(x_events); m_nodeEventHandler.push_back(_n); m_events[_n] = _e; }
Mutex x_events;
std::list<NodeId> m_nodeEventHandler;
std::map<NodeId, NodeTableEventType> m_events;
@ -84,16 +86,16 @@ protected:
class NodeTable;
inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable);
/**
* NodeTable using modified kademlia for node discovery and preference.
* Node table requires an IO service, creates a socket for incoming
* Node table requires an IO service, creates a socket for incoming
* UDP messages and implements a kademlia-like protocol. Node requests and
* responses are used to build a node table which can be queried to
* obtain a list of potential nodes to connect to, and, passes events to
* Host whenever a node is added or removed to/from the table.
*
* Thread-safety is ensured by modifying NodeEntry details via
* Thread-safety is ensured by modifying NodeEntry details via
* shared_ptr replacement instead of mutating values.
*
* NodeTable accepts a port for UDP and will listen to the port on all available
@ -130,69 +132,69 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this<NodeTable>
using NodeSocket = UDPSocket<NodeTable, 1280>;
using TimePoint = std::chrono::steady_clock::time_point;
using EvictionTimeout = std::pair<std::pair<NodeId, TimePoint>, NodeId>; ///< First NodeId may be evicted and replaced with second NodeId.
public:
NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _udpPort = 30303);
~NodeTable();
/// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable.
static unsigned distance(NodeId const& _a, NodeId const& _b) { u512 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; }
/// Set event handler for NodeEntryAdded and NodeEntryRemoved events.
void setEventHandler(NodeTableEventHandler* _handler) { m_nodeEventHandler.reset(_handler); }
/// Called by implementation which provided handler to process NodeEntryAdded/NodeEntryRemoved events. Events are coalesced by type whereby old events are ignored.
void processEvents();
/// Add node. Node will be pinged if it's not already known.
std::shared_ptr<NodeEntry> addNode(Public const& _pubk, bi::udp::endpoint const& _udp, bi::tcp::endpoint const& _tcp);
/// Add node. Node will be pinged if it's not already known.
std::shared_ptr<NodeEntry> addNode(Node const& _node);
/// To be called when node table is empty. Runs node discovery with m_node.id as the target in order to populate node-table.
void discover();
/// Returns list of node ids active in node table.
std::list<NodeId> nodes() const;
/// Returns node count.
unsigned count() const { return m_nodes.size(); }
/// Returns snapshot of table.
std::list<NodeEntry> snapshot() const;
/// Returns true if node id is in node table.
bool haveNode(NodeId const& _id) { Guard l(x_nodes); return m_nodes.count(_id) > 0; }
/// Returns the Node to the corresponding node id or the empty Node if that id is not found.
Node node(NodeId const& _id);
#if defined(BOOST_AUTO_TEST_SUITE) || defined(_MSC_VER) // MSVC includes access specifier in symbol name
protected:
#else
private:
#endif
/// Constants for Kademlia, derived from address space.
static unsigned const s_addressByteSize = sizeof(NodeId); ///< Size of address type in bytes.
static unsigned const s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia].
static unsigned const s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us).
static unsigned const s_maxSteps = boost::static_log2<s_bits>::value; ///< Max iterations of discovery. (discover)
/// Chosen constants
static unsigned const s_bucketSize = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
static unsigned const s_alpha = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests.
/// Intervals
/* todo: replace boost::posix_time; change constants to upper camelcase */
boost::posix_time::milliseconds const c_evictionCheckInterval = boost::posix_time::milliseconds(75); ///< Interval at which eviction timeouts are checked.
std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations).
std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia]
struct NodeBucket
{
unsigned distance;
@ -200,50 +202,50 @@ private:
std::list<std::weak_ptr<NodeEntry>> nodes;
void touch() { modified = std::chrono::steady_clock::now(); }
};
/// Used to ping endpoint.
void ping(bi::udp::endpoint _to) const;
/// Used ping known node. Used by node table when refreshing buckets and as part of eviction process (see evict).
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.
NodeEntry center() const { return NodeEntry(m_node, m_node.publicKey(), m_node.endpoint.udp); }
/// Used by asynchronous operations to return NodeEntry which is active and managed by node table.
std::shared_ptr<NodeEntry> nodeEntry(NodeId _id);
/// Used to discovery nodes on network which are close to the given target.
/// Sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to s_maxSteps rounds.
void discover(NodeId _target, unsigned _round = 0, std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>> _tried = std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>>());
/// Returns nodes from node table which are closest to target.
std::vector<std::shared_ptr<NodeEntry>> nearestNodeEntries(NodeId _target);
/// Asynchronously drops _leastSeen node if it doesn't reply and adds _new node, otherwise _new node is thrown away.
void evict(std::shared_ptr<NodeEntry> _leastSeen, std::shared_ptr<NodeEntry> _new);
/// Called whenever activity is received from an unknown node in order to maintain node table.
void noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint);
/// Used to drop node when timeout occurs or when evict() result is to keep previous node.
void dropNode(std::shared_ptr<NodeEntry> _n);
/// Returns references to bucket which corresponds to distance of node id.
/// @warning Only use the return reference locked x_state mutex.
// TODO p2p: Remove this method after removing offset-by-one functionality.
NodeBucket& bucket_UNSAFE(NodeEntry const* _n);
/// General Network Events
/// Called by m_socket when packet is received.
void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet);
/// Called by m_socket when socket is disconnected.
void onDisconnected(UDPSocketFace*) {}
/// Tasks
/// Called by evict() to ensure eviction check is scheduled to run and terminates when no evictions remain. Asynchronous.
void doCheckEvictions(boost::system::error_code const& _ec);
@ -251,7 +253,7 @@ private:
void doRefreshBuckets(boost::system::error_code const& _ec);
std::unique_ptr<NodeTableEventHandler> m_nodeEventHandler; ///< Event handler for node events.
Node m_node; ///< This node.
Secret m_secret; ///< This nodes secret key.
@ -308,7 +310,7 @@ struct PingNode: RLPXDatagram<PingNode>
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)) {}
static const uint8_t type = 1;
unsigned version = 1;
std::string ipAddress;
unsigned port;
@ -333,7 +335,7 @@ struct Pong: RLPXDatagram<Pong>
h256 echo; ///< MCD of PingNode
unsigned expiration;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << echo << expiration; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); echo = (h256)r[0]; expiration = r[1].toInt<unsigned>(); }
};
@ -357,10 +359,10 @@ struct FindNode: RLPXDatagram<FindNode>
FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram<FindNode>(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {}
static const uint8_t type = 3;
h512 target;
unsigned expiration;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash<h512>(); expiration = r[1].toInt<unsigned>(); }
};
@ -383,7 +385,7 @@ struct Neighbours: RLPXDatagram<Neighbours>
void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; }
void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); port = _r[1].toInt<unsigned>(); node = h512(_r[2].toBytes()); }
};
Neighbours(bi::udp::endpoint _ep): RLPXDatagram<Neighbours>(_ep), 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), expiration(futureFromEpoch(std::chrono::seconds(30)))
{
@ -397,7 +399,7 @@ struct Neighbours: RLPXDatagram<Neighbours>
nodes.push_back(node);
}
}
static const uint8_t type = 4;
std::vector<Node> nodes;
unsigned expiration = 1;

6
libp2p/Session.cpp

@ -24,6 +24,7 @@
#include <chrono>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h>
#include "Host.h"
#include "Capability.h"
@ -467,6 +468,11 @@ void Session::drop(DisconnectReason _reason)
void Session::disconnect(DisconnectReason _reason)
{
clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")";
StructuredLogger::p2pDisconnected(
m_info.id.abridged(),
m_peer->peerEndpoint(),
m_server->peerCount()
);
if (m_socket.is_open())
{
RLPStream s;

3
libp2p/Session.h

@ -27,6 +27,7 @@
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/RangeMask.h>
@ -112,7 +113,7 @@ private:
bool m_dropped = false; ///< If true, we've already divested ourselves of this peer. We're just waiting for the reads & writes to fail before the shared_ptr goes OOS and the destructor kicks in.
PeerSessionInfo m_info; ///< Dynamic information about this peer.
bool m_theyRequestedNodes = false; ///< Has the peer requested nodes from us without receiveing an answer from us?
bool m_weRequestedNodes = false; ///< Have we requested nodes from the peer and not received an answer yet?

53
libp2p/UDP.h

@ -1,16 +1,16 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
@ -26,6 +26,7 @@
#include <vector>
#include <deque>
#include <array>
#include <libdevcore/Guards.h>
#include <libdevcrypto/Common.h>
#include <libdevcrypto/SHA3.h>
@ -49,7 +50,7 @@ public:
UDPDatagram(bi::udp::endpoint const& _ep): locus(_ep) {}
UDPDatagram(bi::udp::endpoint const& _ep, bytes _data): data(_data), locus(_ep) {}
bi::udp::endpoint const& endpoint() const { return locus; }
bytes data;
protected:
bi::udp::endpoint locus;
@ -63,7 +64,7 @@ struct RLPXDatagramFace: public UDPDatagram
static uint64_t futureFromEpoch(std::chrono::milliseconds _ms) { return std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); }
static uint64_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); }
static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp);
virtual uint8_t packetType() = 0;
RLPXDatagramFace(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {}
virtual h256 sign(Secret const& _from);
@ -97,7 +98,7 @@ struct UDPSocketEvents
virtual void onDisconnected(UDPSocketFace*) {};
virtual void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packetData) = 0;
};
/**
* @brief UDP Interface
* Handler must implement UDPSocketEvents.
@ -111,7 +112,7 @@ class UDPSocket: UDPSocketFace, public std::enable_shared_from_this<UDPSocket<Ha
public:
enum { maxDatagramSize = MaxDatagramSize };
static_assert(maxDatagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes");
UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, unsigned _port): m_host(_host), m_endpoint(bi::udp::v4(), _port), m_socket(_io) { m_started.store(false); m_closed.store(true); };
virtual ~UDPSocket() { disconnect(); }
@ -120,32 +121,32 @@ public:
/// Send datagram.
bool send(UDPDatagram const& _datagram);
/// Returns if socket is open.
bool isOpen() { return !m_closed; }
/// Disconnect socket.
void disconnect() { disconnectWithError(boost::asio::error::connection_reset); }
protected:
void doRead();
void doWrite();
void disconnectWithError(boost::system::error_code _ec);
std::atomic<bool> m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start and disconnectWithError.
std::atomic<bool> m_closed; ///< Connection availability.
UDPSocketEvents& m_host; ///< Interface which owns this socket.
bi::udp::endpoint m_endpoint; ///< Endpoint which we listen to.
Mutex x_sendQ;
std::deque<UDPDatagram> m_sendQ; ///< Queue for egress data.
std::array<byte, maxDatagramSize> m_recvData; ///< Buffer for ingress data.
bi::udp::endpoint m_recvEndpoint; ///< Endpoint data was received from.
bi::udp::socket m_socket; ///< Boost asio udp socket.
Mutex x_socketError; ///< Mutex for error which can be set from host or IO thread.
boost::system::error_code m_socketError; ///< Set when shut down due to error.
};
@ -156,29 +157,29 @@ void UDPSocket<Handler, MaxDatagramSize>::connect()
bool expect = false;
if (!m_started.compare_exchange_strong(expect, true))
return;
m_socket.open(bi::udp::v4());
m_socket.bind(m_endpoint);
// clear write queue so reconnect doesn't send stale messages
Guard l(x_sendQ);
m_sendQ.clear();
m_closed = false;
doRead();
}
template <typename Handler, unsigned MaxDatagramSize>
bool UDPSocket<Handler, MaxDatagramSize>::send(UDPDatagram const& _datagram)
{
if (m_closed)
return false;
Guard l(x_sendQ);
m_sendQ.push_back(_datagram);
if (m_sendQ.size() == 1)
doWrite();
return true;
}
@ -187,7 +188,7 @@ void UDPSocket<Handler, MaxDatagramSize>::doRead()
{
if (m_closed)
return;
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this());
m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len)
{
@ -199,13 +200,13 @@ void UDPSocket<Handler, MaxDatagramSize>::doRead()
doRead();
});
}
template <typename Handler, unsigned MaxDatagramSize>
void UDPSocket<Handler, MaxDatagramSize>::doWrite()
{
if (m_closed)
return;
const UDPDatagram& datagram = m_sendQ[0];
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this());
m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t)
@ -244,11 +245,11 @@ void UDPSocket<Handler, MaxDatagramSize>::disconnectWithError(boost::system::err
bool expected = true;
if (!m_started.compare_exchange_strong(expected, false))
return;
// set m_closed to true to prevent undeliverable egress messages
bool wasClosed = m_closed;
m_closed = true;
// close sockets
boost::system::error_code ec;
m_socket.shutdown(bi::udp::socket::shutdown_both, ec);
@ -260,6 +261,6 @@ void UDPSocket<Handler, MaxDatagramSize>::disconnectWithError(boost::system::err
m_host.onDisconnected(this);
}
}
}

2
libserpent/CMakeLists.txt

@ -27,6 +27,6 @@ target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

2
libsolidity/CMakeLists.txt

@ -30,6 +30,6 @@ target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} devcrypto)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

67
libsolidity/Compiler.cpp

@ -205,42 +205,49 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
{
// We do not check the calldata size, everything is zero-padded.
unsigned offset(CompilerUtils::dataStartOffset);
bool const c_padToWords = true;
unsigned dynamicParameterCount = 0;
bigint parameterHeadEnd = offset;
for (TypePointer const& type: _typeParameters)
if (type->isDynamicallySized())
dynamicParameterCount++;
offset += dynamicParameterCount * 32;
unsigned currentDynamicParameter = 0;
parameterHeadEnd += type->isDynamicallySized() ? 32 :
CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
solAssert(parameterHeadEnd <= numeric_limits<unsigned>::max(), "Arguments too large.");
unsigned stackHeightOfPreviousDynamicArgument = 0;
ArrayType const* previousDynamicType = nullptr;
for (TypePointer const& type: _typeParameters)
if (type->isDynamicallySized())
{
switch (type->getCategory())
{
// value on stack: [calldata_offset] (only if we are already in dynamic mode)
if (currentDynamicParameter == 0)
// switch from static to dynamic
case Type::Category::Array:
if (type->isDynamicallySized())
{
// put on stack: data_offset length
unsigned newStackHeight = m_context.getStackHeight();
if (previousDynamicType)
{
// Retrieve data start offset by adding length to start offset of previous dynamic type
unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument;
m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth);
ArrayUtils(m_context).convertLengthToSize(*previousDynamicType);
m_context << u256(32) << eth::Instruction::MUL << eth::Instruction::ADD;
}
else
m_context << u256(parameterHeadEnd);
stackHeightOfPreviousDynamicArgument = newStackHeight;
previousDynamicType = &dynamic_cast<ArrayType const&>(*type);
offset += CompilerUtils(m_context).loadFromMemory(offset, IntegerType(256), !_fromMemory);
}
else
{
m_context << u256(offset);
// retrieve length
CompilerUtils(m_context).loadFromMemory(
CompilerUtils::dataStartOffset + currentDynamicParameter * 32,
IntegerType(256), !_fromMemory, c_padToWords);
// stack: offset length
// add 32-byte padding to copy of length
m_context << u256(32) << eth::Instruction::DUP1 << u256(31)
<< eth::Instruction::DUP4 << eth::Instruction::ADD
<< eth::Instruction::DIV << eth::Instruction::MUL;
// stack: offset length padded_length
m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
currentDynamicParameter++;
// stack: offset length next_calldata_offset
offset += CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
}
break;
default:
solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString());
offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, true);
}
else if (currentDynamicParameter == 0)
// we can still use static load
offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, c_padToWords);
else
CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, c_padToWords);
if (dynamicParameterCount > 0)
m_context << eth::Instruction::POP;
}
}
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)

17
libsolidity/ExpressionCompiler.cpp

@ -984,9 +984,10 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
else
// send all gas except for the 21 needed to execute "SUB" and "CALL"
m_context << u256(21) << eth::Instruction::GAS << eth::Instruction::SUB;
m_context << eth::Instruction::CALL
<< eth::Instruction::POP; // @todo do not ignore failure indicator
m_context << u256(_functionType.valueSet() ? 6741 : 41) << eth::Instruction::GAS << eth::Instruction::SUB;
m_context << eth::Instruction::CALL;
auto tag = m_context.appendConditionalJump();
m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.
if (_functionType.valueSet())
m_context << eth::Instruction::POP;
if (_functionType.gasSet())
@ -999,10 +1000,12 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true);
}
void ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expression const>> const& _arguments,
TypePointers const& _types,
bool _padToWordBoundaries,
bool _padExceptionIfFourBytes)
void ExpressionCompiler::appendArgumentsCopyToMemory(
vector<ASTPointer<Expression const>> const& _arguments,
TypePointers const& _types,
bool _padToWordBoundaries,
bool _padExceptionIfFourBytes
)
{
solAssert(_types.empty() || _types.size() == _arguments.size(), "");
for (size_t i = 0; i < _arguments.size(); ++i)

1
libsolidity/Token.h

@ -46,6 +46,7 @@
#include <libdevcore/Log.h>
#include <libsolidity/Utils.h>
#include <libsolidity/Exceptions.h>
#include <libdevcore/UndefMacros.h>
namespace dev
{

13
libsolidity/Types.cpp

@ -570,6 +570,15 @@ bool ArrayType::operator==(Type const& _other) const
return isDynamicallySized() || getLength() == other.getLength();
}
unsigned ArrayType::getCalldataEncodedSize() const
{
if (isDynamicallySized())
return 0;
bigint size = bigint(getLength()) * (isByteArray() ? 1 : getBaseType()->getCalldataEncodedSize());
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned.");
return unsigned(size);
}
u256 ArrayType::getStorageSize() const
{
if (isDynamicallySized())
@ -586,8 +595,8 @@ u256 ArrayType::getStorageSize() const
unsigned ArrayType::getSizeOnStack() const
{
if (m_location == Location::CallData)
// offset, length (stack top)
return 2;
// offset [length] (stack top)
return 1 + (isDynamicallySized() ? 1 : 0);
else
// offset
return 1;

3
libsolidity/Types.h

@ -30,6 +30,7 @@
#include <libsolidity/Exceptions.h>
#include <libsolidity/ASTForward.h>
#include <libsolidity/Token.h>
#include <libdevcore/UndefMacros.h>
namespace dev
{
@ -67,7 +68,6 @@ private:
MemberMap m_memberTypes;
};
/**
* Abstract base class that forms the root of the type hierarchy.
*/
@ -302,6 +302,7 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override;
virtual unsigned getCalldataEncodedSize() const override;
virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() const override;

3
libweb3jsonrpc/CMakeLists.txt

@ -14,6 +14,7 @@ include_directories(BEFORE ..)
include_directories(${MHD_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE web3jsonrpc)
@ -52,7 +53,7 @@ if (ETH_JSON_RPC_STUB)
add_dependencies(${EXECUTABLE} jsonrpcstub)
endif()
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

3
libweb3jsonrpc/WebThreeStubServer.cpp

@ -21,7 +21,10 @@
* @date 2014
*/
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <libwebthree/WebThree.h>
#include <libdevcrypto/FileSystem.h>
#include "WebThreeStubServer.h"

10
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -21,6 +21,9 @@
* @date 2014
*/
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/SourceReferenceFormatter.h>
@ -89,12 +92,13 @@ static Json::Value toJson(dev::eth::TransactionSkeleton const& _t)
static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e)
{
Json::Value res;
res["data"] = jsFromBinary(_e.data);
res["address"] = toJS(_e.address);
for (auto const& t: _e.topics)
res["topic"].append(toJS(t));
res["number"] = _e.number;
res["hash"] = toJS(_e.sha3);
return res;
}
@ -578,7 +582,7 @@ bool WebThreeStubServerBase::shh_post(Json::Value const& _json)
// TODO: insert validification hook here.
from = m_ids[m.from()];
}
face()->inject(toSealed(_json, m, from));
return true;
}
@ -646,7 +650,7 @@ Json::Value WebThreeStubServerBase::shh_changed(int _id)
continue;
ret.append(toJson(h, e, m));
}
return ret;
}

3
libwebthree/CMakeLists.txt

@ -13,6 +13,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE webthree)
@ -35,6 +36,6 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} secp256k1)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

14
libwebthree/WebThree.cpp

@ -23,7 +23,9 @@
#include <chrono>
#include <thread>
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libp2p/Host.h>
#include <libethereum/Defaults.h>
@ -35,15 +37,21 @@ using namespace dev::p2p;
using namespace dev::eth;
using namespace dev::shh;
WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean, std::set<std::string> const& _interfaces, NetworkPreferences const& _n, bytesConstRef _network, int miners):
WebThreeDirect::WebThreeDirect(
std::string const& _clientVersion,
std::string const& _dbPath,
bool _forceClean,
std::set<std::string> const& _interfaces,
NetworkPreferences const& _n,
bytesConstRef _network, int _miners
):
m_clientVersion(_clientVersion),
m_net(_clientVersion, _n, _network)
{
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
if (_interfaces.count("eth"))
m_ethereum.reset(new eth::Client(&m_net, _dbPath, _forceClean, 0, miners));
m_ethereum.reset(new eth::Client(&m_net, _dbPath, _forceClean, 0, _miners));
if (_interfaces.count("shh"))
m_whisper = m_net.registerCapability<WhisperHost>(new WhisperHost);

16
libwebthree/WebThree.h

@ -25,7 +25,11 @@
#include <mutex>
#include <list>
#include <atomic>
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <boost/utility.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h>
@ -103,7 +107,15 @@ class WebThreeDirect : public WebThreeNetworkFace
public:
/// Constructor for private instance. If there is already another process on the machine using @a _dbPath, then this will throw an exception.
/// ethereum() may be safely static_cast()ed to a eth::Client*.
WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean = false, std::set<std::string> const& _interfaces = {"eth", "shh"}, p2p::NetworkPreferences const& _n = p2p::NetworkPreferences(), bytesConstRef _network = bytesConstRef(), int miners = -1);
WebThreeDirect(
std::string const& _clientVersion,
std::string const& _dbPath,
bool _forceClean = false,
std::set<std::string> const& _interfaces = {"eth", "shh"},
p2p::NetworkPreferences const& _n = p2p::NetworkPreferences(),
bytesConstRef _network = bytesConstRef(),
int _miners = -1
);
/// Destructor.
~WebThreeDirect();
@ -152,7 +164,7 @@ public:
/// Stop the network subsystem.
void stopNetwork() override { m_net.stop(); }
/// Is network working? there may not be any peers yet.
bool isNetworkStarted() const override { return m_net.isStarted(); }

3
libwhisper/CMakeLists.txt

@ -13,6 +13,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE whisper)
@ -32,5 +33,5 @@ target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} p2p)
target_link_libraries(${EXECUTABLE} secp256k1)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

1
libwhisper/Common.h

@ -23,6 +23,7 @@
#include <string>
#include <chrono>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>

1
libwhisper/Interface.h

@ -26,6 +26,7 @@
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcrypto/SHA3.h>

1
libwhisper/Message.h

@ -26,6 +26,7 @@
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcrypto/Common.h>

4
libwhisper/WhisperHost.cpp

@ -58,7 +58,7 @@ void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p)
{
cnote << this << ": inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data());
if (_m.expiry() <= time(0))
if (_m.expiry() <= (unsigned)time(0))
return;
auto h = _m.sha3();
@ -171,7 +171,7 @@ void WhisperHost::cleanup()
{
// remove old messages.
// should be called every now and again.
auto now = time(0);
unsigned now = (unsigned)time(0);
WriteGuard l(x_messages);
for (auto it = m_expiryQueue.begin(); it != m_expiryQueue.end() && it->first <= now; it = m_expiryQueue.erase(it))
m_messages.erase(it->second);

1
libwhisper/WhisperHost.h

@ -26,6 +26,7 @@
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/RLP.h>
#include <libdevcore/Worker.h>
#include <libdevcore/Guards.h>

1
libwhisper/WhisperPeer.h

@ -26,6 +26,7 @@
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcrypto/SHA3.h>

1
mix/CMakeLists.txt

@ -12,6 +12,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(BEFORE ..)
find_package (Qt5WebEngine QUIET)

41
mix/ClientModel.cpp

@ -18,6 +18,9 @@
* Ethereum IDE client.
*/
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <QtConcurrent/QtConcurrent>
#include <QDebug>
#include <QQmlContext>
@ -38,6 +41,7 @@
#include "Web3Server.h"
#include "MixClient.h"
#include "ClientModel.h"
#include "MixClient.h"
using namespace dev;
using namespace dev::eth;
@ -87,7 +91,7 @@ ClientModel::ClientModel(AppContext* _context):
connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection);
m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString()));
m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), std::vector<dev::KeyPair> { m_client->userAccount() }, m_client.get()));
m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_client->userAccounts(), m_client.get()));
connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection);
_context->appEngine()->rootContext()->setContextProperty("clientModel", this);
}
@ -136,6 +140,12 @@ void ClientModel::mine()
});
}
QString ClientModel::newAddress()
{
KeyPair a = KeyPair::create();
return QString::fromStdString(toHex(a.secret().ref()));
}
QVariantMap ClientModel::contractAddresses() const
{
QVariantMap res;
@ -144,16 +154,18 @@ QVariantMap ClientModel::contractAddresses() const
return res;
}
void ClientModel::debugDeployment()
{
executeSequence(std::vector<TransactionSettings>(), 10000000 * ether);
}
void ClientModel::setupState(QVariantMap _state)
{
u256 balance = (qvariant_cast<QEther*>(_state.value("balance")))->toU256Wei();
QVariantList balances = _state.value("accounts").toList();
QVariantList transactions = _state.value("transactions").toList();
std::map<Secret, u256> accounts;
for (auto const& b: balances)
{
QVariantMap address = b.toMap();
accounts.insert(std::make_pair(Secret(address.value("secret").toString().toStdString()), (qvariant_cast<QEther*>(address.value("balance")))->toU256Wei()));
}
std::vector<TransactionSettings> transactionSequence;
for (auto const& t: transactions)
{
@ -163,7 +175,7 @@ void ClientModel::setupState(QVariantMap _state)
u256 gas = boost::get<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue());
u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei();
u256 gasPrice = (qvariant_cast<QEther*>(transaction.value("gasPrice")))->toU256Wei();
QString sender = transaction.value("sender").toString();
bool isStdContract = (transaction.value("stdContract").toBool());
if (isStdContract)
{
@ -173,6 +185,7 @@ void ClientModel::setupState(QVariantMap _state)
transactionSettings.gasPrice = 10000000000000;
transactionSettings.gas = 125000;
transactionSettings.value = 0;
transactionSettings.sender = Secret(sender.toStdString());
transactionSequence.push_back(transactionSettings);
}
else
@ -180,7 +193,7 @@ void ClientModel::setupState(QVariantMap _state)
if (contractId.isEmpty() && m_context->codeModel()->hasContract()) //TODO: This is to support old project files, remove later
contractId = m_context->codeModel()->contracts().keys()[0];
QVariantList qParams = transaction.value("qType").toList();
TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice);
TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice, Secret(sender.toStdString()));
for (QVariant const& variant: qParams)
{
@ -194,10 +207,10 @@ void ClientModel::setupState(QVariantMap _state)
transactionSequence.push_back(transactionSettings);
}
}
executeSequence(transactionSequence, balance);
executeSequence(transactionSequence, accounts);
}
void ClientModel::executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance)
void ClientModel::executeSequence(std::vector<TransactionSettings> const& _sequence, std::map<Secret, u256> const& _balances)
{
if (m_running)
BOOST_THROW_EXCEPTION(ExecutionStateException());
@ -211,7 +224,7 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
{
try
{
m_client->resetState(_balance);
m_client->resetState(_balances);
onStateReset();
for (TransactionSettings const& transaction: _sequence)
{
@ -425,13 +438,13 @@ void ClientModel::showDebugError(QString const& _error)
Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction)
{
Address newAddress = m_client->transact(m_client->userAccount().secret(), _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice);
Address newAddress = m_client->transact(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice);
return newAddress;
}
void ClientModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)
{
m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice);
m_client->transact(_tr.sender, _tr.value, _contract, _data, _tr.gas, _tr.gasPrice);
}
RecordLogEntry* ClientModel::lastBlock() const

11
mix/ClientModel.h

@ -47,8 +47,8 @@ struct SolidityType;
struct TransactionSettings
{
TransactionSettings() {}
TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice):
contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {}
TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice, Secret _sender):
contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice), sender(_sender) {}
TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl):
contractId(_stdContractName), stdContractUrl(_stdContractUrl) {}
@ -66,6 +66,8 @@ struct TransactionSettings
QList<QVariableDefinition*> parameterValues;
/// Standard contract url
QString stdContractUrl;
/// Sender
Secret sender;
};
@ -143,8 +145,6 @@ public:
Q_INVOKABLE void mine();
public slots:
/// Run the contract constructor and show debugger window.
void debugDeployment();
/// Setup state, run transaction sequence, show debugger for the last transaction
/// @param _state JS object with state configuration
void setupState(QVariantMap _state);
@ -152,6 +152,7 @@ public slots:
Q_INVOKABLE void debugRecord(unsigned _index);
/// Show the debugger for an empty record
Q_INVOKABLE void emptyRecord();
Q_INVOKABLE QString newAddress();
private slots:
/// Update UI with machine states result. Display a modal dialog.
@ -192,7 +193,7 @@ signals:
private:
RecordLogEntry* lastBlock() const;
QVariantMap contractAddresses() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance);
void executeSequence(std::vector<TransactionSettings> const& _sequence, std::map<Secret, u256> const& _balances);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
void onNewTransaction();

3
mix/DebuggingStateWrapper.h

@ -22,6 +22,9 @@
#pragma once
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <QStringList>
#include <QHash>
#include <libdevcore/Common.h>

3
mix/Extension.cpp

@ -17,13 +17,16 @@
* Ethereum IDE client.
*/
#include <QMessageBox>
#include <QDebug>
#include <QQmlApplicationEngine>
#include <libevm/VM.h>
#include <libwebthree/WebThree.h>
#include "Extension.h"
#include "AppContext.h"
using namespace dev;
using namespace dev::mix;

22
mix/MixClient.cpp

@ -40,7 +40,7 @@ namespace dev
namespace mix
{
const Secret c_userAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
const Secret c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
const u256 c_mixGenesisDifficulty = (u256) 1 << 4;
class MixBlockChain: public dev::eth::BlockChain
@ -62,16 +62,18 @@ public:
};
MixClient::MixClient(std::string const& _dbPath):
m_userAccount(c_userAccountSecret), m_dbPath(_dbPath), m_minigThreads(0)
m_dbPath(_dbPath), m_minigThreads(0)
{
resetState(10000000 * ether);
std::map<Secret, u256> account;
account.insert(std::make_pair(c_defaultUserAccountSecret, 1000000 * ether));
resetState(account);
}
MixClient::~MixClient()
{
}
void MixClient::resetState(u256 _balance)
void MixClient::resetState(std::map<Secret, u256> _accounts)
{
WriteGuard l(x_state);
Guard fl(m_filterLock);
@ -81,12 +83,20 @@ void MixClient::resetState(u256 _balance)
m_stateDB = OverlayDB();
TrieDB<Address, MemoryDB> accountState(&m_stateDB);
accountState.init();
std::map<Address, Account> genesisState = { std::make_pair(KeyPair(c_userAccountSecret).address(), Account(_balance, Account::NormalCreation)) };
std::map<Address, Account> genesisState;
for (auto account: _accounts)
{
KeyPair a = KeyPair(account.first);
m_userAccounts.push_back(a);
genesisState.insert(std::make_pair(a.address(), Account(account.second, Account::NormalCreation)));
}
dev::eth::commit(genesisState, static_cast<MemoryDB&>(m_stateDB), accountState);
h256 stateRoot = accountState.root();
m_bc.reset();
m_bc.reset(new MixBlockChain(m_dbPath, stateRoot));
m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Empty);
m_state = eth::State(genesisState.begin()->first , m_stateDB, BaseState::Empty);
m_state.sync(bc());
m_startState = m_state;
m_executions.clear();

6
mix/MixClient.h

@ -42,8 +42,7 @@ public:
MixClient(std::string const& _dbPath);
virtual ~MixClient();
/// Reset state to the empty state with given balance.
void resetState(u256 _balance);
KeyPair const& userAccount() const { return m_userAccount; }
void resetState(std::map<Secret, u256> _accounts);
void mine();
ExecutionResult const& lastExecution() const;
ExecutionResults const& executions() const;
@ -91,6 +90,7 @@ public:
bool submitNonce(h256 const&) override { return false; }
/// @returns the last mined block information
eth::BlockInfo blockInfo() const;
std::vector<KeyPair> userAccounts() { return m_userAccounts; }
private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call);
@ -99,7 +99,7 @@ private:
MixBlockChain& bc() { return *m_bc; }
MixBlockChain const& bc() const { return *m_bc; }
KeyPair m_userAccount;
std::vector<KeyPair> m_userAccounts;
eth::State m_state;
eth::State m_startState;
OverlayDB m_stateDB;

1
mix/QContractDefinition.cpp

@ -20,6 +20,7 @@
*/
#include <QObject>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/AST.h>
#include <libsolidity/Scanner.h>

4
mix/qml/Ether.qml

@ -20,7 +20,7 @@ RowLayout {
function update()
{
if (value !== undefined)
if (value)
{
etherValueEdit.text = value.value;
selectUnit(value.unit);
@ -54,7 +54,7 @@ RowLayout {
id: units
onCurrentTextChanged:
{
if (value !== undefined)
if (value)
{
value.setUnit(currentText);
formattedValue.text = value.format();

151
mix/qml/StateDialog.qml

@ -1,5 +1,6 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
import QtQuick.Controls.Styles 1.3
@ -12,24 +13,24 @@ Window {
id: modalStateDialog
modality: Qt.ApplicationModal
width: 520
width: 590
height: 480
title: qsTr("Edit State")
visible: false
color: StateDialogStyle.generic.backgroundColor
property alias stateTitle: titleField.text
property alias stateBalance: balanceField.value
property alias isDefault: defaultCheckBox.checked
property int stateIndex
property var stateTransactions: []
property var stateAccounts: []
signal accepted
function open(index, item, setDefault) {
stateIndex = index;
stateTitle = item.title;
balanceField.value = item.balance;
transactionsModel.clear();
stateTransactions = [];
var transactions = item.transactions;
for (var t = 0; t < transactions.length; t++) {
@ -37,6 +38,14 @@ Window {
stateTransactions.push(item.transactions[t]);
}
accountsModel.clear();
stateAccounts = [];
for (var k = 0; k < item.accounts.length; k++)
{
accountsModel.append(item.accounts[k]);
stateAccounts.push(item.accounts[k]);
}
modalStateDialog.setX((Screen.width - width) / 2);
modalStateDialog.setY((Screen.height - height) / 2);
@ -54,10 +63,11 @@ Window {
function getItem() {
var item = {
title: stateDialog.stateTitle,
balance: stateDialog.stateBalance,
transactions: []
transactions: [],
accounts: []
}
item.transactions = stateTransactions;
item.accounts = stateAccounts;
return item;
}
@ -90,15 +100,112 @@ Window {
RowLayout
{
Layout.fillWidth: true
DefaultLabel {
Rectangle
{
Layout.preferredWidth: 75
text: qsTr("Balance")
DefaultLabel {
id: accountsLabel
Layout.preferredWidth: 75
text: qsTr("Accounts")
}
Button
{
anchors.top: accountsLabel.bottom
anchors.topMargin: 10
iconSource: "qrc:/qml/img/plus.png"
action: newAccountAction
}
Action {
id: newAccountAction
tooltip: qsTr("Add new Account")
onTriggered:
{
var account = stateListModel.newAccount("1000000", QEther.Ether);
stateAccounts.push(account);
accountsModel.append(account);
}
}
}
Ether {
id: balanceField
edit: true
displayFormattedValue: true
MessageDialog
{
id: alertAlreadyUsed
text: qsTr("This account is in use. You cannot remove it. The first account is used to deploy config contract and cannot be removed.")
icon: StandardIcon.Warning
standardButtons: StandardButton.Ok
}
TableView
{
id: accountsView
Layout.fillWidth: true
model: accountsModel
headerVisible: false
TableViewColumn {
role: "name"
title: qsTr("Name")
width: 150
delegate: Item {
RowLayout
{
height: 25
width: parent.width
Button
{
iconSource: "qrc:/qml/img/delete_sign.png"
action: deleteAccountAction
}
Action {
id: deleteAccountAction
tooltip: qsTr("Delete Account")
onTriggered:
{
if (transactionsModel.isUsed(stateAccounts[styleData.row].secret))
alertAlreadyUsed.open();
else
{
stateAccounts.splice(styleData.row, 1);
accountsModel.remove(styleData.row);
}
}
}
DefaultTextField {
anchors.verticalCenter: parent.verticalCenter
onTextChanged: {
if (styleData.row > -1)
stateAccounts[styleData.row].name = text;
}
text: {
return styleData.value
}
}
}
}
}
TableViewColumn {
role: "balance"
title: qsTr("Balance")
width: 200
delegate: Item {
Ether {
id: balanceField
edit: true
displayFormattedValue: false
value: styleData.value
}
}
}
rowDelegate:
Rectangle {
color: styleData.alternate ? "transparent" : "#f0f0f0"
height: 30;
}
}
}
@ -196,10 +303,21 @@ Window {
}
}
ListModel {
id: accountsModel
function removeAccount(_i)
{
accountsModel.remove(_i);
stateAccounts.splice(_i, 1);
}
}
ListModel {
id: transactionsModel
function editTransaction(index) {
transactionDialog.stateAccounts = stateAccounts;
transactionDialog.open(index, transactionsModel.get(index));
}
@ -209,6 +327,7 @@ Window {
// https://bugreports.qt-project.org/browse/QTBUG-41327
// Second call to signal handler would just edit the item that was just created, no harm done
var item = TransactionHelper.defaultTransaction();
transactionDialog.stateAccounts = stateAccounts;
transactionDialog.open(transactionsModel.count, item);
}
@ -216,6 +335,16 @@ Window {
stateTransactions.splice(index, 1);
transactionsModel.remove(index);
}
function isUsed(secret)
{
for (var i in stateTransactions)
{
if (stateTransactions[i].sender === secret)
return true;
}
return false;
}
}
Component {

59
mix/qml/StateListModel.qml

@ -11,25 +11,39 @@ Item {
property alias model: stateListModel
property var stateList: []
property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project
function fromPlainStateItem(s) {
if (!s.accounts)
s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project
return {
title: s.title,
balance: QEtherHelper.createEther(s.balance.value, s.balance.unit),
transactions: s.transactions.map(fromPlainTransactionItem)
transactions: s.transactions.map(fromPlainTransactionItem),
accounts: s.accounts.map(fromPlainAccountItem)
};
}
function fromPlainAccountItem(t)
{
return {
name: t.name,
secret: t.secret,
balance: QEtherHelper.createEther(t.balance.value, t.balance.unit)
};
}
function fromPlainTransactionItem(t) {
if (!t.sender)
t.sender = defaultAccount; //support for old project
var r = {
contractId: t.contractId,
functionId: t.functionId,
url: t.url,
value: QEtherHelper.createEther(t.value.value, t.value.unit),
gas: QEtherHelper.createBigInt(t.gas.value), //t.gas,//QEtherHelper.createEther(t.gas.value, t.gas.unit),
gas: QEtherHelper.createBigInt(t.gas.value),
gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit),
stdContract: t.stdContract,
parameters: {}
parameters: {},
sender: t.sender
};
var qType = [];
for (var key in t.parameters)
@ -65,8 +79,8 @@ Item {
function toPlainStateItem(s) {
return {
title: s.title,
balance: { value: s.balance.value, unit: s.balance.unit },
transactions: s.transactions.map(toPlainTransactionItem)
transactions: s.transactions.map(toPlainTransactionItem),
accounts: s.accounts.map(toPlainAccountItem)
};
}
@ -80,6 +94,18 @@ Item {
return '';
}
function toPlainAccountItem(t)
{
return {
name: t.name,
secret: t.secret,
balance: {
value: t.balance.value,
unit: t.balance.unit
}
};
}
function toPlainTransactionItem(t) {
var r = {
contractId: t.contractId,
@ -152,7 +178,6 @@ Item {
ListModel {
id: stateListModel
property int defaultStateIndex: 0
signal defaultStateChanged;
signal stateListModelReady;
@ -167,15 +192,23 @@ Item {
};
}
function newAccount(_balance, _unit, _secret)
{
if (!_secret)
_secret = clientModel.newAddress();
var name = qsTr("Account") + "-" + _secret.substring(0, 4);
return { name: name, secret: _secret, balance: QEtherHelper.createEther(_balance, _unit) };
}
function createDefaultState() {
//var ether = QEtherHelper.createEther("100000000000000000000000000", QEther.Wei);
var ether = QEtherHelper.createEther("1000000", QEther.Ether);
var item = {
title: "",
balance: ether,
transactions: []
transactions: [],
accounts: []
};
item.accounts.push(newAccount("1000000", QEther.Ether, defaultAccount));
//add all stdc contracts
for (var i = 0; i < contractLibrary.model.count; i++) {
var contractTransaction = defaultTransactionItem();
@ -184,6 +217,7 @@ Item {
contractTransaction.contractId = contractItem.name;
contractTransaction.functionId = contractItem.name;
contractTransaction.stdContract = true;
contractTransaction.sender = item.accounts[0].secret; // default account is used to deploy std contract.
item.transactions.push(contractTransaction);
};
@ -192,6 +226,7 @@ Item {
var ctorTr = defaultTransactionItem();
ctorTr.functionId = c;
ctorTr.contractId = c;
ctorTr.sender = item.accounts[0].secret;
item.transactions.push(ctorTr);
}
return item;

2
mix/qml/StatusPane.qml

@ -164,8 +164,6 @@ Rectangle {
RowLayout
{
anchors.fill: parent
anchors.top: parent.top
anchors.right: parent.right
Rectangle
{
color: "transparent"

33
mix/qml/TransactionDialog.qml

@ -25,6 +25,7 @@ Window {
property var itemParams;
property bool useTransactionDefaultValue: false
property var qType;
property alias stateAccounts: senderComboBox.model
signal accepted;
@ -44,6 +45,8 @@ Window {
rowFunction.visible = true;
itemParams = item.parameters !== undefined ? item.parameters : {};
if (item.sender)
senderComboBox.select(item.sender);
contractsModel.clear();
var contractIndex = -1;
@ -190,6 +193,7 @@ Window {
item.functionId = transactionDialog.functionId;
}
item.sender = senderComboBox.model[senderComboBox.currentIndex].secret;
var orderedQType = [];
for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
var parameter = transactionDialog.transactionParams.get(p);
@ -210,6 +214,35 @@ Window {
id: dialogContent
anchors.top: parent.top
spacing: 10
RowLayout
{
id: rowSender
Layout.fillWidth: true
height: 150
DefaultLabel {
Layout.preferredWidth: 75
text: qsTr("Sender")
}
ComboBox {
function select(secret)
{
for (var i in model)
if (model[i].secret === secret)
{
currentIndex = i;
break;
}
}
id: senderComboBox
Layout.preferredWidth: 350
currentIndex: 0
textRole: "name"
editable: false
}
}
RowLayout
{
id: rowContract

6
mix/qml/TransactionLog.qml

@ -38,6 +38,12 @@ Item {
if (codeModel.hasContract && !clientModel.running)
projectModel.stateListModel.debugDefaultState();
}
onProjectClosed:
{
fullModel.clear();
transactionModel.clear();
callModel.clear();
}
}
ComboBox {

1
neth/CMakeLists.txt

@ -5,6 +5,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE neth)

2
neth/main.cpp

@ -25,8 +25,10 @@
#include <fstream>
#include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libethereum/All.h>

14
secp256k1/CMakeLists.txt

@ -21,6 +21,18 @@ if (APPLE OR UNIX)
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -DUSE_FIELD_GMP -DUSE_NUM_GMP -DUSE_FIELD_INV_NUM")
target_link_libraries(${EXECUTABLE} ${GMP_LIBRARIES})
elseif (CMAKE_COMPILER_IS_MINGW)
include_directories(${Boost_INCLUDE_DIRS})
if (ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${EXECUTABLE}.c field_5x52_asm.asm)
else()
add_library(${EXECUTABLE} SHARED ${EXECUTABLE}.c field_5x52_asm.asm)
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -W -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -DUSE_FIELD_GMP -DUSE_NUM_GMP -DUSE_FIELD_INV_NUM")
target_link_libraries(${EXECUTABLE} ${GMP_LIBRARIES})
else()
include_directories(${Boost_INCLUDE_DIRS})
@ -36,5 +48,5 @@ else()
endif()
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

19
test/SolidityEndToEndTest.cpp

@ -1619,9 +1619,11 @@ BOOST_AUTO_TEST_CASE(gas_and_value_basic)
function sendAmount(uint amount) returns (uint256 bal) {
return h.getBalance.value(amount)();
}
function outOfGas() returns (bool flagBefore, bool flagAfter, uint myBal) {
flagBefore = h.getFlag();
h.setFlag.gas(2)(); // should fail due to OOG, return value can be garbage
function outOfGas() returns (bool ret) {
h.setFlag.gas(2)(); // should fail due to OOG
return true;
}
function checkState() returns (bool flagAfter, uint myBal) {
flagAfter = h.getFlag();
myBal = this.balance;
}
@ -1630,7 +1632,8 @@ BOOST_AUTO_TEST_CASE(gas_and_value_basic)
compileAndRun(sourceCode, 20);
BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5));
// call to helper should not succeed but amount should be transferred anyway
BOOST_REQUIRE(callContractFunction("outOfGas()", 5) == encodeArgs(false, false, 20 - 5));
BOOST_REQUIRE(callContractFunction("outOfGas()", 5) == bytes());
BOOST_REQUIRE(callContractFunction("checkState()", 5) == encodeArgs(false, 20 - 5));
}
BOOST_AUTO_TEST_CASE(value_complex)
@ -2504,11 +2507,11 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete)
compileAndRun(sourceCode);
string data = "123456789012345678901234567890123";
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true));
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data) == encodeArgs(true));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("copy()") == encodeArgs(true));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true));
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data) == encodeArgs(true));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("del()") == encodeArgs(true));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
@ -2661,8 +2664,8 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments)
bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13);
string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3));
bytes calldata = encodeArgs(
u256(innercalldata1.length()), u256(innercalldata2.length()),
12, innercalldata1, innercalldata2, 13);
12, u256(innercalldata1.length()), u256(innercalldata2.length()), 13,
innercalldata1, innercalldata2);
BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata)
== encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())));
}

4
test/TestHelper.cpp

@ -23,7 +23,9 @@
#include <thread>
#include <chrono>
#include <boost/filesystem/path.hpp>
#include <libethereum/Client.h>
#include <liblll/Compiler.h>
#include <libevm/VMFactory.h>
@ -170,7 +172,7 @@ void ImportTest::importTransaction(json_spirit::mObject& _o)
}
}
void ImportTest::exportTest(bytes _output, State& _statePost)
void ImportTest::exportTest(bytes const& _output, State const& _statePost)
{
// export output
m_TestObject["out"] = "0x" + toHex(_output);

4
test/TestHelper.h

@ -22,7 +22,9 @@
#pragma once
#include <functional>
#include <boost/test/unit_test.hpp>
#include "JsonSpiritHeaders.h"
#include <libethereum/State.h>
#include <libevm/ExtVMFace.h>
@ -52,7 +54,7 @@ public:
void importEnv(json_spirit::mObject& _o);
void importState(json_spirit::mObject& _o, eth::State& _state);
void importTransaction(json_spirit::mObject& _o);
void exportTest(bytes _output, eth::State& _statePost);
void exportTest(bytes const& _output, eth::State const& _statePost);
eth::State m_statePre;
eth::State m_statePost;

144
test/block.cpp

@ -81,6 +81,76 @@ bytes createBlockRLPFromFields(mObject& _tObj)
return rlpStream.out();
}
void overwriteBlockHeader(mObject& _o, BlockInfo _current_BlockHeader)
{
if (_o.count("blockHeader"))
{
if (_o["blockHeader"].get_obj().size() != 14)
{
BlockInfo tmp = _current_BlockHeader;
if (_o["blockHeader"].get_obj().count("parentHash"))
tmp.parentHash = h256(_o["blockHeader"].get_obj()["parentHash"].get_str());
if (_o["blockHeader"].get_obj().count("uncleHash"))
tmp.sha3Uncles = h256(_o["blockHeader"].get_obj()["uncleHash"].get_str());
if (_o["blockHeader"].get_obj().count("coinbase"))
tmp.coinbaseAddress = Address(_o["blockHeader"].get_obj()["coinbase"].get_str());
if (_o["blockHeader"].get_obj().count("stateRoot"))
tmp.stateRoot = h256(_o["blockHeader"].get_obj()["stateRoot"].get_str());
if (_o["blockHeader"].get_obj().count("transactionsTrie"))
tmp.transactionsRoot = h256(_o["blockHeader"].get_obj()["transactionsTrie"].get_str());
if (_o["blockHeader"].get_obj().count("receiptTrie"))
tmp.receiptsRoot = h256(_o["blockHeader"].get_obj()["receiptTrie"].get_str());
if (_o["blockHeader"].get_obj().count("bloom"))
tmp.logBloom = LogBloom(_o["blockHeader"].get_obj()["bloom"].get_str());
if (_o["blockHeader"].get_obj().count("difficulty"))
tmp.difficulty = toInt(_o["blockHeader"].get_obj()["difficulty"]);
if (_o["blockHeader"].get_obj().count("number"))
tmp.number = toInt(_o["blockHeader"].get_obj()["number"]);
if (_o["blockHeader"].get_obj().count("gasLimit"))
tmp.gasLimit = toInt(_o["blockHeader"].get_obj()["gasLimit"]);
if (_o["blockHeader"].get_obj().count("gasUsed"))
tmp.gasUsed = toInt(_o["blockHeader"].get_obj()["gasUsed"]);
if (_o["blockHeader"].get_obj().count("timestamp"))
tmp.timestamp = toInt(_o["blockHeader"].get_obj()["timestamp"]);
if (_o["blockHeader"].get_obj().count("extraData"))
tmp.extraData = importByteArray(_o["blockHeader"].get_obj()["extraData"].get_str());
// find new valid nonce
if (tmp != _current_BlockHeader)
{
_current_BlockHeader = tmp;
cout << "new header!\n";
ProofOfWork pow;
MineInfo ret;
while (!ProofOfWork::verify(_current_BlockHeader.headerHash(WithoutNonce), _current_BlockHeader.nonce, _current_BlockHeader.difficulty))
tie(ret, _current_BlockHeader.nonce) = pow.mine(_current_BlockHeader.headerHash(WithoutNonce), _current_BlockHeader.difficulty, 10000, true, true);
}
}
else
{
// take the blockheader as is
const bytes c_blockRLP = createBlockRLPFromFields(_o["blockHeader"].get_obj());
const RLP c_bRLP(c_blockRLP);
_current_BlockHeader.populateFromHeader(c_bRLP, false);
}
}
}
void doBlockTests(json_spirit::mValue& _v, bool _fillin)
{
for (auto& i: _v.get_obj())
@ -214,76 +284,9 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin)
BlockInfo current_BlockHeader = state.info();
// overwrite blockheader with (possible wrong) data from "blockheader" in filler;
if (o.count("blockHeader"))
{
if (o["blockHeader"].get_obj().size() != 14)
{
BlockInfo tmp = current_BlockHeader;
if (o["blockHeader"].get_obj().count("parentHash"))
tmp.parentHash = h256(o["blockHeader"].get_obj()["parentHash"].get_str());
if (o["blockHeader"].get_obj().count("uncleHash"))
tmp.sha3Uncles = h256(o["blockHeader"].get_obj()["uncleHash"].get_str());
if (o["blockHeader"].get_obj().count("coinbase"))
tmp.coinbaseAddress = Address(o["blockHeader"].get_obj()["coinbase"].get_str());
if (o["blockHeader"].get_obj().count("stateRoot"))
tmp.stateRoot = h256(o["blockHeader"].get_obj()["stateRoot"].get_str());
if (o["blockHeader"].get_obj().count("transactionsTrie"))
tmp.transactionsRoot = h256(o["blockHeader"].get_obj()["transactionsTrie"].get_str());
if (o["blockHeader"].get_obj().count("receiptTrie"))
tmp.receiptsRoot = h256(o["blockHeader"].get_obj()["receiptTrie"].get_str());
if (o["blockHeader"].get_obj().count("bloom"))
tmp.logBloom = LogBloom(o["blockHeader"].get_obj()["bloom"].get_str());
if (o["blockHeader"].get_obj().count("difficulty"))
tmp.difficulty = toInt(o["blockHeader"].get_obj()["difficulty"]);
if (o["blockHeader"].get_obj().count("number"))
tmp.number = toInt(o["blockHeader"].get_obj()["number"]);
if (o["blockHeader"].get_obj().count("gasLimit"))
tmp.gasLimit = toInt(o["blockHeader"].get_obj()["gasLimit"]);
if (o["blockHeader"].get_obj().count("gasUsed"))
tmp.gasUsed = toInt(o["blockHeader"].get_obj()["gasUsed"]);
if (o["blockHeader"].get_obj().count("timestamp"))
tmp.timestamp = toInt(o["blockHeader"].get_obj()["timestamp"]);
if (o["blockHeader"].get_obj().count("extraData"))
tmp.extraData = importByteArray(o["blockHeader"].get_obj()["extraData"].get_str());
// find new valid nonce
if (tmp != current_BlockHeader)
{
current_BlockHeader = tmp;
cout << "new header!\n";
ProofOfWork pow;
MineInfo ret;
while (!ProofOfWork::verify(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.nonce, current_BlockHeader.difficulty))
tie(ret, current_BlockHeader.nonce) = pow.mine(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.difficulty, 10000, true, true);
}
}
else
{
// take the blockheader as is
const bytes c_blockRLP = createBlockRLPFromFields(o["blockHeader"].get_obj());
const RLP c_bRLP(c_blockRLP);
current_BlockHeader.populateFromHeader(c_bRLP, false);
}
}
overwriteBlockHeader(o, current_BlockHeader);
// write block header
mObject oBlockHeader;
oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash);
oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles);
@ -423,7 +426,6 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin)
BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!");
//Check transaction list
Transactions txsFromField;
for (auto const& txObj: o["transactions"].get_array())
@ -511,9 +513,9 @@ BOOST_AUTO_TEST_CASE(blForkBlocks)
dev::test::executeTests("blForkBlocks", "/BlockTests", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_CASE(userDefinedFileBl)
BOOST_AUTO_TEST_CASE(userDefinedFile)
{
dev::test::userDefinedTest("--bltest", dev::test::doBlockTests);
dev::test::userDefinedTest("--singletest", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_SUITE_END()

2
test/createRandomTest.cpp

@ -23,8 +23,10 @@
#include <string>
#include <iostream>
#include <chrono>
#include <boost/random.hpp>
#include <boost/filesystem/path.hpp>
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <json_spirit/json_spirit.h>
#include <json_spirit/json_spirit_reader_template.h>

1
test/fork.cpp

@ -22,6 +22,7 @@
#include <boost/test/unit_test.hpp>
#include <boost/filesystem/operations.hpp>
#include <libethereum/Client.h>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/EthereumHost.h>

6
test/genesis.cpp

@ -22,10 +22,12 @@
#include <fstream>
#include <random>
#include <boost/test/unit_test.hpp>
#include "JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
#include <libethereum/CanonBlockChain.h>
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
using namespace std;
@ -40,7 +42,7 @@ BOOST_AUTO_TEST_CASE(emptySHA3Types)
{
h256 emptyListSHA3(fromHex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"));
BOOST_REQUIRE_EQUAL(emptyListSHA3, EmptyListSHA3);
h256 emptySHA3(fromHex("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
BOOST_REQUIRE_EQUAL(emptySHA3, EmptySHA3);
}

8
test/hexPrefix.cpp

@ -21,11 +21,13 @@
*/
#include <fstream>
#include <boost/test/unit_test.hpp>
#include "JsonSpiritHeaders.h"
#include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieCommon.h>
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
using namespace std;
@ -53,8 +55,8 @@ BOOST_AUTO_TEST_CASE(hexPrefix_test)
for (auto& i: o["seq"].get_array())
v.push_back((byte)i.get_int());
auto e = hexPrefixEncode(v, o["term"].get_bool());
BOOST_REQUIRE( ! o["out"].is_null() );
BOOST_CHECK( o["out"].get_str() == toHex(e) );
BOOST_REQUIRE( ! o["out"].is_null() );
BOOST_CHECK( o["out"].get_str() == toHex(e) );
}
}

37
test/net.cpp

@ -20,6 +20,7 @@
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/Worker.h>
#include <libdevcrypto/Common.h>
#include <libp2p/UDP.h>
@ -43,7 +44,7 @@ public:
void start() { startWorking(); }
void doWork() { m_io.run(); }
void doneWorking() { m_io.reset(); m_io.poll(); m_io.reset(); }
protected:
ba::io_service m_io;
};
@ -52,23 +53,23 @@ struct TestNodeTable: public NodeTable
{
/// Constructor
TestNodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _port = 30300): NodeTable(_io, _alias, _port) {}
static std::vector<std::pair<KeyPair,unsigned>> createTestNodes(unsigned _count)
{
std::vector<std::pair<KeyPair,unsigned>> ret;
asserts(_count < 1000);
static uint16_t s_basePort = 30500;
ret.clear();
for (unsigned i = 0; i < _count; i++)
{
KeyPair k = KeyPair::create();
ret.push_back(make_pair(k,s_basePort+i));
}
return std::move(ret);
}
void pingTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes)
{
bi::address ourIp = bi::address::from_string("127.0.0.1");
@ -78,7 +79,7 @@ struct TestNodeTable: public NodeTable
this_thread::sleep_for(chrono::milliseconds(2));
}
}
void populateTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes, size_t _count = 0)
{
if (!_count)
@ -91,7 +92,7 @@ struct TestNodeTable: public NodeTable
else
break;
}
void reset()
{
Guard l(x_state);
@ -108,13 +109,13 @@ struct TestNodeTableHost: public TestHost
~TestNodeTableHost() { m_io.stop(); stopWorking(); }
void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared<TestNodeTable>(m_io,n.first,n.second)); }
void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); }
void populateAll(size_t _count = 0) { for (auto& t: nodeTables) t->populateTestNodes(testNodes, _count); }
void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); }
KeyPair m_alias;
shared_ptr<TestNodeTable> nodeTable;
std::vector<std::pair<KeyPair,unsigned>> testNodes; // keypair and port
@ -130,7 +131,7 @@ public:
void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; }
shared_ptr<UDPSocket<TestUDPSocket, 1024>> m_socket;
bool success = false;
};
@ -139,7 +140,7 @@ BOOST_AUTO_TEST_CASE(test_neighbours_packet)
KeyPair k = KeyPair::create();
std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);
Neighbours out(to);
for (auto n: testNodes)
{
@ -186,25 +187,25 @@ BOOST_AUTO_TEST_CASE(kademlia)
node.setup();
node.populate();
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
node.populateAll();
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
auto nodes = node.nodeTable->nodes();
nodes.sort();
node.nodeTable->reset();
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
node.populate(1);
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
node.nodeTable->discover();
this_thread::sleep_for(chrono::milliseconds(2000));
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
BOOST_REQUIRE_EQUAL(node.nodeTable->count(), 8);
auto netNodes = node.nodeTable->nodes();
netNodes.sort();

146
test/rlp.cpp

@ -22,11 +22,13 @@
#include <fstream>
#include <sstream>
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <boost/test/unit_test.hpp>
#include <algorithm>
#include "JsonSpiritHeaders.h"
#include "TestHelper.h"
@ -66,76 +68,76 @@ namespace dev
testPath += "/BasicTests";
string s = asString(contents(testPath + "/rlptest.json"));
BOOST_REQUIRE_MESSAGE( s.length() > 0,
"Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?");
BOOST_REQUIRE_MESSAGE( s.length() > 0,
"Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);
}
}
static void checkRLPTestCase(js::mObject& o)
{
BOOST_REQUIRE( o.count("in") > 0 );
BOOST_REQUIRE( o.count("out") > 0 );
BOOST_REQUIRE(!o["out"].is_null());
}
{
BOOST_REQUIRE( o.count("in") > 0 );
BOOST_REQUIRE( o.count("out") > 0 );
BOOST_REQUIRE(!o["out"].is_null());
}
static void checkRLPAgainstJson(js::mValue& v, RLP& u)
{
if ( v.type() == js::str_type )
{
if ( v.type() == js::str_type )
{
const std::string& expectedText = v.get_str();
if ( !expectedText.empty() && expectedText.front() == '#' )
{
// Deal with bigint instead of a raw string
std::string bigIntStr = expectedText.substr(1,expectedText.length()-1);
std::stringstream bintStream(bigIntStr);
bigint val;
bintStream >> val;
BOOST_CHECK( !u.isList() );
if ( !expectedText.empty() && expectedText.front() == '#' )
{
// Deal with bigint instead of a raw string
std::string bigIntStr = expectedText.substr(1,expectedText.length()-1);
std::stringstream bintStream(bigIntStr);
bigint val;
bintStream >> val;
BOOST_CHECK( !u.isList() );
BOOST_CHECK( !u.isNull() );
BOOST_CHECK( u ); // operator bool()
BOOST_CHECK(u == val);
}
else
{
BOOST_CHECK( !u.isList() );
BOOST_CHECK( !u.isNull() );
BOOST_CHECK( u.isData() );
BOOST_CHECK( u );
BOOST_CHECK( u.size() == expectedText.length() );
BOOST_CHECK(u == expectedText);
BOOST_CHECK(u == val);
}
else
{
BOOST_CHECK( !u.isList() );
BOOST_CHECK( !u.isNull() );
BOOST_CHECK( u.isData() );
BOOST_CHECK( u );
BOOST_CHECK( u.size() == expectedText.length() );
BOOST_CHECK(u == expectedText);
}
}
else if ( v.type() == js::int_type )
{
const int expectedValue = v.get_int();
BOOST_CHECK( u.isInt() );
BOOST_CHECK( !u.isList() );
}
else if ( v.type() == js::int_type )
{
const int expectedValue = v.get_int();
BOOST_CHECK( u.isInt() );
BOOST_CHECK( !u.isList() );
BOOST_CHECK( !u.isNull() );
BOOST_CHECK( u ); // operator bool()
BOOST_CHECK(u == expectedValue);
}
else if ( v.type() == js::array_type )
{
BOOST_CHECK( u.isList() );
BOOST_CHECK( !u.isInt() );
BOOST_CHECK( !u.isData() );
js::mArray& arr = v.get_array();
BOOST_CHECK( u.itemCount() == arr.size() );
unsigned i;
for( i = 0; i < arr.size(); i++ )
{
RLP item = u[i];
checkRLPAgainstJson(arr[i], item);
}
}
else
{
BOOST_CHECK(u == expectedValue);
}
else if ( v.type() == js::array_type )
{
BOOST_CHECK( u.isList() );
BOOST_CHECK( !u.isInt() );
BOOST_CHECK( !u.isData() );
js::mArray& arr = v.get_array();
BOOST_CHECK( u.itemCount() == arr.size() );
unsigned i;
for( i = 0; i < arr.size(); i++ )
{
RLP item = u[i];
checkRLPAgainstJson(arr[i], item);
}
}
else
{
BOOST_ERROR("Invalid Javascript object!");
}
}
}
}
}
}
}
BOOST_AUTO_TEST_SUITE(BasicTests)
@ -154,30 +156,30 @@ BOOST_AUTO_TEST_CASE(rlp_encoding_test)
RLPStream s;
dev::test::buildRLP(o["in"], s);
std::string expectedText(o["out"].get_str());
std::transform(expectedText.begin(), expectedText.end(), expectedText.begin(), ::tolower );
std::string expectedText(o["out"].get_str());
std::transform(expectedText.begin(), expectedText.end(), expectedText.begin(), ::tolower );
const std::string& computedText = toHex(s.out());
const std::string& computedText = toHex(s.out());
std::stringstream msg;
std::stringstream msg;
msg << "Encoding Failed: expected: " << expectedText << std::endl;
msg << " But Computed: " << computedText;
msg << " But Computed: " << computedText;
BOOST_CHECK_MESSAGE(
expectedText == computedText,
expectedText == computedText,
msg.str()
);
);
}
}
BOOST_AUTO_TEST_CASE(rlp_decoding_test)
{
cnote << "Testing RLP decoding...";
// Uses the same test cases as encoding but in reverse.
// We read into the string of hex values, convert to bytes,
// and then compare the output structure to the json of the
// input object.
cnote << "Testing RLP decoding...";
// Uses the same test cases as encoding but in reverse.
// We read into the string of hex values, convert to bytes,
// and then compare the output structure to the json of the
// input object.
js::mValue v;
dev::test::getRLPTestCases(v);
for (auto& i: v.get_obj())
@ -185,11 +187,11 @@ BOOST_AUTO_TEST_CASE(rlp_decoding_test)
js::mObject& o = i.second.get_obj();
cnote << i.first;
dev::test::checkRLPTestCase(o);
js::mValue& inputData = o["in"];
bytes payloadToDecode = fromHex(o["out"].get_str());
bytes payloadToDecode = fromHex(o["out"].get_str());
RLP payload(payloadToDecode);
RLP payload(payloadToDecode);
dev::test::checkRLPAgainstJson(inputData, payload);

3
test/state.cpp

@ -22,6 +22,7 @@
#include <boost/filesystem/operations.hpp>
#include <boost/test/unit_test.hpp>
#include "JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
#include <libethereum/CanonBlockChain.h>
@ -241,7 +242,7 @@ BOOST_AUTO_TEST_CASE(stCreateTest)
BOOST_AUTO_TEST_CASE(userDefinedFileState)
{
dev::test::userDefinedTest("--statetest", dev::test::doStateTests);
dev::test::userDefinedTest("--singletest", dev::test::doStateTests);
}
BOOST_AUTO_TEST_SUITE_END()

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save