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 ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
qt5_wrap_ui(ui_Main.h Main.ui) qt5_wrap_ui(ui_Main.h Main.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui) qt5_wrap_ui(ui_Debugger.h Debugger.ui)

13
alethzero/MainWin.cpp

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

1
alethzero/MainWin.h

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

3
alethzero/Transact.cpp

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

2
cmake/EthCompilerSettings.cmake

@ -3,7 +3,7 @@
# C++11 check and activation # C++11 check and activation
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") 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_DEBUG "-O0 -g -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -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 # only look in default directories
find_path( find_path(
JSON_RPC_CPP_INCLUDE_DIR JSON_RPC_CPP_INCLUDE_DIR
NAMES jsonrpccpp/server.h NAMES jsonrpccpp/server.h jsonrpc/server.h
PATH_SUFFIXES jsonrpc PATH_SUFFIXES jsonrpc
DOC "json-rpc-cpp include dir" 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 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 automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
RUN apt-get install -qy libncurses5-dev libcurl4-openssl-dev wget
# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 ) RUN apt-get install -qy libjsoncpp-dev libargtable2-dev libmicrohttpd-dev
RUN apt-get install -qy libncurses5-dev
# Qt-based GUI
# RUN apt-get install -qy qtbase5-dev qt5-default qtdeclarative5-dev libqt5webkit5-dev
# Ethereum PPA # Ethereum PPA
RUN apt-get install -qy software-properties-common RUN apt-get install -qy software-properties-common
RUN add-apt-repository ppa:ethereum/ethereum RUN add-apt-repository ppa:ethereum/ethereum
RUN add-apt-repository ppa:ethereum/ethereum-dev
RUN apt-get update RUN apt-get update
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev 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) # Build Ethereum (HEADLESS)
RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum
RUN mkdir -p cpp-ethereum/build 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 RUN ldconfig
ENTRYPOINT ["/usr/local/bin/eth"] ENTRYPOINT ["/usr/local/bin/eth"]

2
eth/CMakeLists.txt

@ -28,7 +28,7 @@ endif()
target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1) 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}") add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
endif() endif()

88
eth/main.cpp

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

2
libethcore/CMakeLists.txt

@ -25,6 +25,6 @@ endif()
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore) 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

14
libethereum/BlockChain.cpp

@ -25,6 +25,7 @@
#include <test/JsonSpiritHeaders.h> #include <test/JsonSpiritHeaders.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/StructuredLogger.h>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
@ -317,6 +318,13 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
} }
#endif #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."; // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children.";
h256s ret; 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)); 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); 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 else
{ {

2
libethereum/BlockChain.h

@ -96,7 +96,7 @@ public:
BlockInfo info(h256 _hash) const { return BlockInfo(block(_hash)); } BlockInfo info(h256 _hash) const { return BlockInfo(block(_hash)); }
BlockInfo info() const { return BlockInfo(block()); } 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(h256 _hash) const { return queryExtras<BlockDetails, 0>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); } BlockDetails details() const { return details(currentHash()); }

7
libethereum/CMakeLists.txt

@ -13,6 +13,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE ethereum) set(EXECUTABLE ethereum)
@ -35,6 +36,10 @@ target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} secp256k1) 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

36
libethereum/Client.cpp

@ -25,6 +25,7 @@
#include <thread> #include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/StructuredLogger.h>
#include <libp2p/Host.h> #include <libp2p/Host.h>
#include "Defaults.h" #include "Defaults.h"
#include "Executive.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"), Worker("eth"),
m_vc(_dbPath), m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean), 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)); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (miners > -1) if (_miners > -1)
setMiningThreads(miners); setMiningThreads(_miners);
else else
setMiningThreads(); setMiningThreads();
if (_dbPath.size()) if (_dbPath.size())
@ -291,7 +292,7 @@ LocalisedLogEntries Client::checkWatch(unsigned _watchId)
return ret; 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); Guard l(m_filterLock);
for (pair<h256 const, InstalledFilter>& i: m_filters) for (pair<h256 const, InstalledFilter>& i: m_filters)
@ -303,7 +304,7 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& i
{ {
// filter catches them // filter catches them
for (LogEntry const& l: m) 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); 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) 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)) 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. // 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); auto m = i.second.filter.matches(tr);
if (m.size()) if (m.size())
{ {
auto sha3 = transaction(d.hash, j).sha3();
// filter catches them // filter catches them
for (LogEntry const& l: m) 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); 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); 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)); // 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; cnote << "New transaction " << t;
m_tq.attemptImport(t.rlp()); m_tq.attemptImport(t.rlp());
} }
@ -582,8 +586,9 @@ void Client::doWork()
TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq); TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq);
if (newPendingReceipts.size()) if (newPendingReceipts.size())
{ {
for (auto i: newPendingReceipts) for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(i, changeds); appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
changeds.insert(PendingChangedFilter); changeds.insert(PendingChangedFilter);
if (isMining()) if (isMining())
@ -756,6 +761,7 @@ LocalisedLogEntries Client::logs(LogFilter const& _f) const
{ {
// Might have a transaction that contains a matching log. // Might have a transaction that contains a matching log.
TransactionReceipt const& tr = m_postMine.receipt(i); TransactionReceipt const& tr = m_postMine.receipt(i);
auto sha3 = m_postMine.pending()[i].sha3();
LogEntries le = _f.matches(tr); LogEntries le = _f.matches(tr);
if (le.size()) if (le.size())
{ {
@ -763,7 +769,7 @@ LocalisedLogEntries Client::logs(LogFilter const& _f) const
if (s) if (s)
s--; s--;
else else
ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin)); ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, sha3));
} }
} }
begin = m_bc.number(); begin = m_bc.number();
@ -782,11 +788,15 @@ LocalisedLogEntries Client::logs(LogFilter const& _f) const
int total = 0; int total = 0;
#endif #endif
// check block bloom // check block bloom
if (_f.matches(m_bc.info(h).logBloom)) auto info = m_bc.info(h);
for (TransactionReceipt receipt: m_bc.receipts(h).receipts) 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())) if (_f.matches(receipt.bloom()))
{ {
auto h = transaction(info.hash, i).sha3();
LogEntries le = _f.matches(receipt); LogEntries le = _f.matches(receipt);
if (le.size()) if (le.size())
{ {
@ -798,7 +808,7 @@ LocalisedLogEntries Client::logs(LogFilter const& _f) const
if (s) if (s)
s--; s--;
else 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 <atomic>
#include <string> #include <string>
#include <array> #include <array>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
@ -44,6 +46,7 @@
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
@ -166,7 +169,13 @@ class Client: public MinerHost, public Interface, Worker
public: public:
/// New-style Constructor. /// 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. /// Destructor.
virtual ~Client(); virtual ~Client();
@ -220,7 +229,7 @@ public:
/// @returns the length of the chain. /// @returns the length of the chain.
virtual unsigned number() const { return m_bc.number(); } 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(). /// @TODO: Remove in favour of transactions().
virtual Transactions pending() const { return m_postMine.pending(); } virtual Transactions pending() const { return m_postMine.pending(); }
@ -311,7 +320,7 @@ public:
protected: protected:
/// Collate the changed filters for the bloom filter of the given pending transaction. /// Collate the changed filters for the bloom filter of the given pending transaction.
/// Insert any filters that are activated into @a o_changed. /// 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. /// Collate the changed filters for the hash of the given block.
/// Insert any filters that are activated into @a o_changed. /// Insert any filters that are activated into @a o_changed.

1
libethereum/EthereumHost.h

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

4
libethereum/EthereumPeer.h

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

1
libethereum/Miner.h

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

7
libethereum/State.cpp

@ -27,6 +27,7 @@
#include <boost/timer.hpp> #include <boost/timer.hpp>
#include <secp256k1/secp256k1.h> #include <secp256k1/secp256k1.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/StructuredLogger.h>
#include <libevmcore/Instruction.h> #include <libevmcore/Instruction.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
@ -820,6 +821,12 @@ void State::completeMine()
ret.swapOut(m_currentBytes); ret.swapOut(m_currentBytes);
m_currentBlock.hash = sha3(RLP(m_currentBytes)[0].data()); m_currentBlock.hash = sha3(RLP(m_currentBytes)[0].data());
cnote << "Mined " << m_currentBlock.hash.abridged() << "(parent: " << m_currentBlock.parentHash.abridged() << ")"; 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. // Quickly reset the transactions.
// TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. // 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} ethcore)
target_link_libraries(${EXECUTABLE} secp256k1) 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

2
libevm/CMakeLists.txt

@ -34,6 +34,6 @@ if (EVMJIT)
target_link_libraries(${EXECUTABLE} evmjit-cpp) target_link_libraries(${EXECUTABLE} evmjit-cpp)
endif() 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

3
libevm/ExtVMFace.h

@ -63,9 +63,10 @@ using LogEntries = std::vector<LogEntry>;
struct LocalisedLogEntry: public LogEntry struct LocalisedLogEntry: public LogEntry
{ {
LocalisedLogEntry() {} 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; unsigned number = 0;
h256 sha3;
}; };
using LocalisedLogEntries = std::vector<LocalisedLogEntry>; using LocalisedLogEntries = std::vector<LocalisedLogEntry>;

2
libevmcore/CMakeLists.txt

@ -26,6 +26,6 @@ endif()
target_link_libraries(${EXECUTABLE} devcore) 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

2
libjsqrc/CMakeLists.txt

@ -22,4 +22,4 @@ if (ETH_NODE AND ETH_NPM)
add_dependencies(jsqrc ethereumjs) add_dependencies(jsqrc ethereumjs)
endif() 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.** **Please note this repo is in it's early stage.**
If you'd like to run a WebSocket ethereum node check out If you'd like to run a Http ethereum node check out
[go-ethereum](https://github.com/ethereum/go-ethereum). [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 eth -j
ethereum -ws -loglevel=4
``` ```
[npm-image]: https://badge.fury.io/js/ethereum.js.png [npm-image]: https://badge.fury.io/js/ethereum.js.png

2
libjsqrc/ethereumjs/bower.json

@ -1,7 +1,7 @@
{ {
"name": "ethereum.js", "name": "ethereum.js",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.0.15", "version": "0.0.16",
"description": "Ethereum Compatible JavaScript API", "description": "Ethereum Compatible JavaScript API",
"main": [ "main": [
"./dist/ethereum.js", "./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 * @date 2014
*/ */
var web3 = require('./web3');
var utils = require('./utils'); var utils = require('./utils');
var types = require('./types'); var types = require('./types');
var c = require('./const'); var c = require('./const');
@ -41,11 +40,11 @@ var arrayType = function (type) {
var dynamicTypeBytes = function (type, value) { var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings // TODO: decide what to do with array of strings
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. 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 ""; return "";
}; };
var inputTypes = types.inputTypes(); var inputTypes = types.inputTypes();
/// Formats input params to bytes /// Formats input params to bytes
/// @param abi contract method inputs /// @param abi contract method inputs
@ -53,13 +52,16 @@ var inputTypes = types.inputTypes();
/// @returns bytes representation of input params /// @returns bytes representation of input params
var formatInput = function (inputs, params) { var formatInput = function (inputs, params) {
var bytes = ""; 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) { inputs.forEach(function (input, index) {
bytes += dynamicTypeBytes(input.type, params[index]); bytes += dynamicTypeBytes(input.type, params[index]);
}); });
inputs.forEach(function (input, i) { inputs.forEach(function (input, i) {
/*jshint maxcomplexity:5 */
var typeMatch = false; var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) { for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
typeMatch = inputTypes[j].type(inputs[i].type, params[i]); 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 formatter = inputTypes[j - 1].format;
var toAppend = "";
if (arrayType(inputs[i].type)) if (arrayType(inputs[i].type))
toAppend = params[i].reduce(function (acc, curr) { toAppendArrayContent += params[i].reduce(function (acc, curr) {
return acc + formatter(curr); return acc + formatter(curr);
}, ""); }, "");
else if (inputs[i].type === 'string')
toAppendArrayContent += formatter(params[i]);
else else
toAppend = formatter(params[i]); toAppendConstant += formatter(params[i]);
bytes += toAppend;
}); });
bytes += toAppendConstant + toAppendArrayContent;
return bytes; return bytes;
}; };
@ -89,14 +93,14 @@ var dynamicBytesLength = function (type) {
return 0; return 0;
}; };
var outputTypes = types.outputTypes(); var outputTypes = types.outputTypes();
/// Formats output bytes back to param list /// Formats output bytes back to param list
/// @param contract abi method outputs /// @param contract abi method outputs
/// @param bytes representtion of output /// @param bytes representtion of output
/// @returns array of output params /// @returns array of output params
var formatOutput = function (outs, output) { var formatOutput = function (outs, output) {
output = output.slice(2); output = output.slice(2);
var result = []; var result = [];
var padding = c.ETH_PADDING * 2; var padding = c.ETH_PADDING * 2;
@ -104,7 +108,7 @@ var formatOutput = function (outs, output) {
var dynamicPartLength = outs.reduce(function (acc, curr) { var dynamicPartLength = outs.reduce(function (acc, curr) {
return acc + dynamicBytesLength(curr.type); return acc + dynamicBytesLength(curr.type);
}, 0); }, 0);
var dynamicPart = output.slice(0, dynamicPartLength); var dynamicPart = output.slice(0, dynamicPartLength);
output = output.slice(dynamicPartLength); output = output.slice(dynamicPartLength);
@ -125,13 +129,13 @@ var formatOutput = function (outs, output) {
dynamicPart = dynamicPart.slice(padding); dynamicPart = dynamicPart.slice(padding);
var array = []; var array = [];
for (var k = 0; k < size; k++) { 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); output = output.slice(padding);
} }
result.push(array); result.push(array);
} }
else if (types.prefixedType('string')(outs[i].type)) { else if (types.prefixedType('string')(outs[i].type)) {
dynamicPart = dynamicPart.slice(padding); dynamicPart = dynamicPart.slice(padding);
result.push(formatter(output.slice(0, padding))); result.push(formatter(output.slice(0, padding)));
output = output.slice(padding); output = output.slice(padding);
} else { } else {
@ -149,14 +153,14 @@ var formatOutput = function (outs, output) {
var inputParser = function (json) { var inputParser = function (json) {
var parser = {}; var parser = {};
json.forEach(function (method) { json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name); var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name); var typeName = utils.extractTypeName(method.name);
var impl = function () { var impl = function () {
var params = Array.prototype.slice.call(arguments); var params = Array.prototype.slice.call(arguments);
return formatInput(method.inputs, params); return formatInput(method.inputs, params);
}; };
if (parser[displayName] === undefined) { if (parser[displayName] === undefined) {
parser[displayName] = impl; parser[displayName] = impl;
} }
@ -173,7 +177,7 @@ var outputParser = function (json) {
var parser = {}; var parser = {};
json.forEach(function (method) { json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name); var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name); var typeName = utils.extractTypeName(method.name);
var impl = function (output) { var impl = function (output) {
@ -190,27 +194,14 @@ var outputParser = function (json) {
return parser; 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 = { module.exports = {
inputParser: inputParser, inputParser: inputParser,
outputParser: outputParser, outputParser: outputParser,
formatInput: formatInput, formatInput: formatInput,
formatOutput: formatOutput, formatOutput: formatOutput
signatureFromAscii: signatureFromAscii,
eventSignatureFromAscii: eventSignatureFromAscii
}; };
},{"./const":2,"./formatters":8,"./types":15,"./utils":16}],2:[function(require,module,exports){
},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -296,6 +287,7 @@ var web3 = require('./web3');
var abi = require('./abi'); var abi = require('./abi');
var utils = require('./utils'); var utils = require('./utils');
var eventImpl = require('./event'); var eventImpl = require('./event');
var signature = require('./signature');
var exportNatspecGlobals = function (vars) { var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js // it's used byt natspec.js
@ -343,12 +335,12 @@ var addFunctionsToContract = function (contract, desc, address) {
var impl = function () { var impl = function () {
/*jshint maxcomplexity:7 */ /*jshint maxcomplexity:7 */
var params = Array.prototype.slice.call(arguments); 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 parsed = inputParser[displayName][typeName].apply(null, params);
var options = contract._options || {}; var options = contract._options || {};
options.to = address; options.to = address;
options.data = signature + parsed; options.data = sign + parsed;
var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant); var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);
var collapse = options.collapse !== false; var collapse = options.collapse !== false;
@ -402,7 +394,7 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) {
Object.defineProperty(contract, 'topic', { Object.defineProperty(contract, 'topic', {
get: function() { get: function() {
return utils.filterEvents(desc).map(function (e) { 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 impl = function () {
var params = Array.prototype.slice.call(arguments); var params = Array.prototype.slice.call(arguments);
var signature = abi.eventSignatureFromAscii(e.name); var sign = signature.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, signature, e); var event = eventImpl.inputParser(address, sign, e);
var o = event.apply(null, params); var o = event.apply(null, params);
var outputFormatter = function (data) { var outputFormatter = function (data) {
var parser = eventImpl.outputParser(e); var parser = eventImpl.outputParser(e);
@ -489,7 +481,7 @@ var contract = function (address, desc) {
module.exports = contract; 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. This file is part of ethereum.js.
@ -638,6 +630,7 @@ module.exports = {
var abi = require('./abi'); var abi = require('./abi');
var utils = require('./utils'); var utils = require('./utils');
var signature = require('./signature');
/// filter inputs array && returns only indexed (or not) inputs /// filter inputs array && returns only indexed (or not) inputs
/// @param inputs array /// @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' // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'
return function (indexed, options) { return function (indexed, options) {
var o = options || {}; var o = options || {};
o.address = address; o.address = address;
o.topic = []; o.topic = [];
o.topic.push(signature); o.topic.push(sign);
if (indexed) { if (indexed) {
o.topic = o.topic.concat(indexedParamsToTopics(event, indexed)); o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));
} }
@ -712,6 +705,7 @@ var outputParser = function (event) {
var result = { var result = {
event: utils.extractDisplayName(event.name), event: utils.extractDisplayName(event.name),
number: output.number, number: output.number,
hash: output.hash,
args: {} args: {}
}; };
@ -735,8 +729,8 @@ var outputParser = function (event) {
var getMatchingEvent = function (events, payload) { var getMatchingEvent = function (events, payload) {
for (var i = 0; i < events.length; i++) { for (var i = 0; i < events.length; i++) {
var signature = abi.eventSignatureFromAscii(events[i].name); var sign = signature.eventSignatureFromAscii(events[i].name);
if (signature === payload.topic[0]) { if (sign === payload.topic[0]) {
return events[i]; 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. 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. 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 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/>. 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 /** @file types.js
* @authors: * @authors:
* Marek Kotewicz <marek@ethdev.com> * 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. 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. 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. This file is part of ethereum.js.
@ -1796,7 +1834,7 @@ setupMethods(shhWatch, watches.shh());
module.exports = web3; 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'); var web3 = require('./lib/web3');
web3.providers.HttpSyncProvider = require('./lib/httpsync'); web3.providers.HttpSyncProvider = require('./lib/httpsync');
web3.providers.QtSyncProvider = require('./lib/qtsync'); web3.providers.QtSyncProvider = require('./lib/qtsync');
@ -1805,7 +1843,7 @@ web3.abi = require('./lib/abi');
module.exports = web3; 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 //# 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 * @date 2014
*/ */
var web3 = require('./web3');
var utils = require('./utils'); var utils = require('./utils');
var types = require('./types'); var types = require('./types');
var c = require('./const'); var c = require('./const');
@ -40,11 +39,11 @@ var arrayType = function (type) {
var dynamicTypeBytes = function (type, value) { var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings // TODO: decide what to do with array of strings
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. 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 ""; return "";
}; };
var inputTypes = types.inputTypes(); var inputTypes = types.inputTypes();
/// Formats input params to bytes /// Formats input params to bytes
/// @param abi contract method inputs /// @param abi contract method inputs
@ -52,13 +51,16 @@ var inputTypes = types.inputTypes();
/// @returns bytes representation of input params /// @returns bytes representation of input params
var formatInput = function (inputs, params) { var formatInput = function (inputs, params) {
var bytes = ""; 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) { inputs.forEach(function (input, index) {
bytes += dynamicTypeBytes(input.type, params[index]); bytes += dynamicTypeBytes(input.type, params[index]);
}); });
inputs.forEach(function (input, i) { inputs.forEach(function (input, i) {
/*jshint maxcomplexity:5 */
var typeMatch = false; var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) { for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
typeMatch = inputTypes[j].type(inputs[i].type, params[i]); 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 formatter = inputTypes[j - 1].format;
var toAppend = "";
if (arrayType(inputs[i].type)) if (arrayType(inputs[i].type))
toAppend = params[i].reduce(function (acc, curr) { toAppendArrayContent += params[i].reduce(function (acc, curr) {
return acc + formatter(curr); return acc + formatter(curr);
}, ""); }, "");
else if (inputs[i].type === 'string')
toAppendArrayContent += formatter(params[i]);
else else
toAppend = formatter(params[i]); toAppendConstant += formatter(params[i]);
bytes += toAppend;
}); });
bytes += toAppendConstant + toAppendArrayContent;
return bytes; return bytes;
}; };
@ -88,14 +92,14 @@ var dynamicBytesLength = function (type) {
return 0; return 0;
}; };
var outputTypes = types.outputTypes(); var outputTypes = types.outputTypes();
/// Formats output bytes back to param list /// Formats output bytes back to param list
/// @param contract abi method outputs /// @param contract abi method outputs
/// @param bytes representtion of output /// @param bytes representtion of output
/// @returns array of output params /// @returns array of output params
var formatOutput = function (outs, output) { var formatOutput = function (outs, output) {
output = output.slice(2); output = output.slice(2);
var result = []; var result = [];
var padding = c.ETH_PADDING * 2; var padding = c.ETH_PADDING * 2;
@ -103,7 +107,7 @@ var formatOutput = function (outs, output) {
var dynamicPartLength = outs.reduce(function (acc, curr) { var dynamicPartLength = outs.reduce(function (acc, curr) {
return acc + dynamicBytesLength(curr.type); return acc + dynamicBytesLength(curr.type);
}, 0); }, 0);
var dynamicPart = output.slice(0, dynamicPartLength); var dynamicPart = output.slice(0, dynamicPartLength);
output = output.slice(dynamicPartLength); output = output.slice(dynamicPartLength);
@ -124,13 +128,13 @@ var formatOutput = function (outs, output) {
dynamicPart = dynamicPart.slice(padding); dynamicPart = dynamicPart.slice(padding);
var array = []; var array = [];
for (var k = 0; k < size; k++) { 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); output = output.slice(padding);
} }
result.push(array); result.push(array);
} }
else if (types.prefixedType('string')(outs[i].type)) { else if (types.prefixedType('string')(outs[i].type)) {
dynamicPart = dynamicPart.slice(padding); dynamicPart = dynamicPart.slice(padding);
result.push(formatter(output.slice(0, padding))); result.push(formatter(output.slice(0, padding)));
output = output.slice(padding); output = output.slice(padding);
} else { } else {
@ -148,14 +152,14 @@ var formatOutput = function (outs, output) {
var inputParser = function (json) { var inputParser = function (json) {
var parser = {}; var parser = {};
json.forEach(function (method) { json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name); var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name); var typeName = utils.extractTypeName(method.name);
var impl = function () { var impl = function () {
var params = Array.prototype.slice.call(arguments); var params = Array.prototype.slice.call(arguments);
return formatInput(method.inputs, params); return formatInput(method.inputs, params);
}; };
if (parser[displayName] === undefined) { if (parser[displayName] === undefined) {
parser[displayName] = impl; parser[displayName] = impl;
} }
@ -172,7 +176,7 @@ var outputParser = function (json) {
var parser = {}; var parser = {};
json.forEach(function (method) { json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name); var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name); var typeName = utils.extractTypeName(method.name);
var impl = function (output) { var impl = function (output) {
@ -189,22 +193,9 @@ var outputParser = function (json) {
return parser; 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 = { module.exports = {
inputParser: inputParser, inputParser: inputParser,
outputParser: outputParser, outputParser: outputParser,
formatInput: formatInput, formatInput: formatInput,
formatOutput: formatOutput, formatOutput: formatOutput
signatureFromAscii: signatureFromAscii,
eventSignatureFromAscii: eventSignatureFromAscii
}; };

11
libjsqrc/ethereumjs/lib/contract.js

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

10
libjsqrc/ethereumjs/lib/event.js

@ -22,6 +22,7 @@
var abi = require('./abi'); var abi = require('./abi');
var utils = require('./utils'); var utils = require('./utils');
var signature = require('./signature');
/// filter inputs array && returns only indexed (or not) inputs /// filter inputs array && returns only indexed (or not) inputs
/// @param inputs array /// @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' // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'
return function (indexed, options) { return function (indexed, options) {
var o = options || {}; var o = options || {};
o.address = address; o.address = address;
o.topic = []; o.topic = [];
o.topic.push(signature); o.topic.push(sign);
if (indexed) { if (indexed) {
o.topic = o.topic.concat(indexedParamsToTopics(event, indexed)); o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));
} }
@ -96,6 +97,7 @@ var outputParser = function (event) {
var result = { var result = {
event: utils.extractDisplayName(event.name), event: utils.extractDisplayName(event.name),
number: output.number, number: output.number,
hash: output.hash,
args: {} args: {}
}; };
@ -119,8 +121,8 @@ var outputParser = function (event) {
var getMatchingEvent = function (events, payload) { var getMatchingEvent = function (events, payload) {
for (var i = 0; i < events.length; i++) { for (var i = 0; i < events.length; i++) {
var signature = abi.eventSignatureFromAscii(events[i].name); var sign = signature.eventSignatureFromAscii(events[i].name);
if (signature === payload.topic[0]) { if (sign === payload.topic[0]) {
return events[i]; 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", "name": "ethereum.js",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.0.15", "version": "0.0.16",
"description": "Ethereum Compatible JavaScript API", "description": "Ethereum Compatible JavaScript API",
"main": "./index.js", "main": "./index.js",
"directories": { "directories": {

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

@ -29,7 +29,7 @@ describe('abi', function() {
d[0].inputs = [ d[0].inputs = [
{ type: "uint" } { type: "uint" }
]; ];
// when // when
var parser = abi.inputParser(d); var parser = abi.inputParser(d);
@ -37,7 +37,7 @@ describe('abi', function() {
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a"); assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
); );
assert.equal( assert.equal(
@ -67,7 +67,7 @@ describe('abi', function() {
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a"); assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
); );
assert.equal( assert.equal(
@ -80,7 +80,7 @@ describe('abi', function() {
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003"); assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
}); });
it('should parse input uint256', function() { it('should parse input uint256', function() {
// given // given
@ -97,7 +97,7 @@ describe('abi', function() {
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a"); assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
); );
assert.equal( assert.equal(
@ -108,7 +108,7 @@ describe('abi', function() {
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003"); assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000"); assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003"); assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
}); });
it('should parse input int', function() { it('should parse input int', function() {
@ -119,7 +119,7 @@ describe('abi', function() {
d[0].inputs = [ d[0].inputs = [
{ type: "int" } { type: "int" }
]; ];
// when // when
var parser = abi.inputParser(d); var parser = abi.inputParser(d);
@ -130,7 +130,7 @@ describe('abi', function() {
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0"); assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
); );
assert.equal( assert.equal(
@ -162,7 +162,7 @@ describe('abi', function() {
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0"); assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
); );
assert.equal( assert.equal(
@ -177,7 +177,7 @@ describe('abi', function() {
}); });
it('should parse input int256', function() { it('should parse input int256', function() {
// given // given
var d = clone(description); var d = clone(description);
@ -195,7 +195,7 @@ describe('abi', function() {
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0"); assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
); );
assert.equal( assert.equal(
@ -206,11 +206,11 @@ describe('abi', function() {
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003"); assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000"); assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003"); assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
}); });
it('should parse input bool', function() { it('should parse input bool', function() {
// given // given
var d = clone(description); var d = clone(description);
@ -235,14 +235,14 @@ describe('abi', function() {
d[0].inputs = [ d[0].inputs = [
{ type: "hash" } { type: "hash" }
]; ];
// when // when
var parser = abi.inputParser(d); var parser = abi.inputParser(d);
// then // then
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"); assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
}); });
it('should parse input hash256', function() { it('should parse input hash256', function() {
@ -272,7 +272,7 @@ describe('abi', function() {
// when // when
var parser = abi.inputParser(d); var parser = abi.inputParser(d);
// then // then
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"); assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
}); });
@ -285,17 +285,17 @@ describe('abi', function() {
d[0].inputs = [ d[0].inputs = [
{ type: "address" } { type: "address" }
]; ];
// when // when
var parser = abi.inputParser(d) var parser = abi.inputParser(d)
// then // then
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"); assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
}); });
it('should parse input string', function () { it('should parse input string', function () {
// given // given
var d = clone(description); var d = clone(description);
@ -308,8 +308,9 @@ describe('abi', function() {
// then // then
assert.equal( assert.equal(
parser.test('hello'), parser.test('hello'),
"000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000"
); );
assert.equal( assert.equal(
parser.test('world'), 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 () { it('should use proper method name', function () {
// given // given
var d = clone(description); var d = clone(description);
d[0].name = 'helloworld(int)'; d[0].name = 'helloworld(int)';
@ -334,9 +379,9 @@ describe('abi', function() {
assert.equal(parser.helloworld['int'](1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal(parser.helloworld['int'](1), "0000000000000000000000000000000000000000000000000000000000000001");
}); });
it('should parse multiple methods', function () { it('should parse multiple methods', function () {
// given // given
var d = [{ var d = [{
name: "test", name: "test",
@ -356,14 +401,14 @@ describe('abi', function() {
//then //then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal( assert.equal(
parser.test2('hello'), parser.test2('hello'),
"000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000" "000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"
); );
}); });
it('should parse input array of ints', function () { it('should parse input array of ints', function () {
// given // given
var d = clone(description); var d = clone(description);
@ -377,14 +422,91 @@ describe('abi', function() {
// then // then
assert.equal( assert.equal(
parser.test([5, 6]), parser.test([5, 6]),
"0000000000000000000000000000000000000000000000000000000000000002" + "0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" + "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" "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 () { it('should parse input real', function () {
// given // given
var d = clone(description); var d = clone(description);
@ -396,15 +518,15 @@ describe('abi', function() {
var parser = abi.inputParser(d); var parser = abi.inputParser(d);
// then // then
assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000"); assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000"); assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000"); assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000");
assert.equal(parser.test([-1]), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000"); assert.equal(parser.test([-1]), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000");
}); });
it('should parse input ureal', function () { it('should parse input ureal', function () {
// given // given
var d = clone(description); var d = clone(description);
@ -416,12 +538,11 @@ describe('abi', function() {
var parser = abi.inputParser(d); var parser = abi.inputParser(d);
// then // then
assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000"); assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000"); assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000"); 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} evmcore)
target_link_libraries(${EXECUTABLE} devcore) 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} ) 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) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE natspec) set(EXECUTABLE natspec)
@ -31,5 +32,5 @@ target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Qml) target_link_libraries(${EXECUTABLE} Qt5::Qml)
target_link_libraries(${EXECUTABLE} devcore) 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} ) 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 # 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 # and windows is failing to build without that
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
if (MINIUPNPC_FOUND) if (MINIUPNPC_FOUND)
include_directories(${MINIUPNPC_INCLUDE_DIRS}) include_directories(${MINIUPNPC_INCLUDE_DIRS})
@ -37,6 +38,10 @@ endif()
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore) 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

3
libp2p/Common.h

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

113
libp2p/Host.cpp

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

66
libp2p/Host.h

@ -30,6 +30,7 @@
#include <utility> #include <utility>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h> #include <libdevcore/RangeMask.h>
@ -56,7 +57,7 @@ public:
HostNodeTableHandler(Host& _host); HostNodeTableHandler(Host& _host);
Host const& host() const { return m_host; } Host const& host() const { return m_host; }
private: private:
virtual void processEvent(NodeId const& _n, NodeTableEventType const& _e); virtual void processEvent(NodeId const& _n, NodeTableEventType const& _e);
@ -82,23 +83,27 @@ class Host: public Worker
friend class HostNodeTableHandler; friend class HostNodeTableHandler;
friend class Session; friend class Session;
friend class HostCapabilityFace; friend class HostCapabilityFace;
public: public:
/// Start server, listening for connections on the given port. /// 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. /// Will block on network process events.
virtual ~Host(); virtual ~Host();
/// Interval at which Host::run will call keepAlivePeers to ping peers. /// Interval at which Host::run will call keepAlivePeers to ping peers.
std::chrono::seconds const c_keepAliveInterval = std::chrono::seconds(30); std::chrono::seconds const c_keepAliveInterval = std::chrono::seconds(30);
/// Disconnect timeout after failure to respond to keepAlivePeers ping. /// Disconnect timeout after failure to respond to keepAlivePeers ping.
std::chrono::milliseconds const c_keepAliveTimeOut = std::chrono::milliseconds(1000); std::chrono::milliseconds const c_keepAliveTimeOut = std::chrono::milliseconds(1000);
/// Default host for current version of client. /// Default host for current version of client.
static std::string pocHost(); static std::string pocHost();
/// Basic peer network protocol version. /// Basic peer network protocol version.
unsigned protocolVersion() const; unsigned protocolVersion() const;
@ -108,23 +113,23 @@ public:
bool haveCapability(CapDesc const& _name) const { return m_capabilities.count(_name) != 0; } 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; } 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; } } 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; } 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); void addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPort, unsigned short _udpPort);
/// Set ideal number of peers. /// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; } void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
/// Get peer information. /// Get peer information.
PeerSessionInfos peerSessionInfo() const; PeerSessionInfos peerSessionInfo() const;
/// Get number of peers connected. /// Get number of peers connected.
size_t peerCount() const; size_t peerCount() const;
/// Get the address we're listening on currently. /// Get the address we're listening on currently.
std::string listenAddress() const { return m_tcpPublic.address().to_string(); } std::string listenAddress() const { return m_tcpPublic.address().to_string(); }
/// Get the port we're listening on currently. /// Get the port we're listening on currently.
unsigned short listenPort() const { return m_tcpPublic.port(); } unsigned short listenPort() const { return m_tcpPublic.port(); }
@ -138,11 +143,11 @@ public:
/// Start network. @threadsafe /// Start network. @threadsafe
void start(); void start();
/// Stop network. @threadsafe /// Stop network. @threadsafe
/// Resets acceptor, socket, and IO service. Called by deallocator. /// Resets acceptor, socket, and IO service. Called by deallocator.
void stop(); void stop();
/// @returns if network is running. /// @returns if network is running.
bool isStarted() const { return m_run; } bool isStarted() const { return m_run; }
@ -155,25 +160,25 @@ protected:
/// Deserialise the data and populate the set of known peers. /// Deserialise the data and populate the set of known peers.
void restoreNetwork(bytesConstRef _b); void restoreNetwork(bytesConstRef _b);
private: private:
/// Populate m_peerAddresses with available public addresses. /// Populate m_peerAddresses with available public addresses.
void determinePublic(std::string const& _publicAddress, bool _upnp); void determinePublic(std::string const& _publicAddress, bool _upnp);
void connect(std::shared_ptr<Peer> const& _p); void connect(std::shared_ptr<Peer> const& _p);
/// Ping the peers to update the latency information and disconnect peers which have timed out. /// Ping the peers to update the latency information and disconnect peers which have timed out.
void keepAlivePeers(); void keepAlivePeers();
/// Disconnect peers which didn't respond to keepAlivePeers ping prior to c_keepAliveTimeOut. /// Disconnect peers which didn't respond to keepAlivePeers ping prior to c_keepAliveTimeOut.
void disconnectLatePeers(); void disconnectLatePeers();
/// Called only from startedWorking(). /// Called only from startedWorking().
void runAcceptor(); 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. /// 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 doHandshake(bi::tcp::socket* _socket, NodeId _nodeId = NodeId());
void seal(bytes& _b); void seal(bytes& _b);
/// Called by Worker. Not thread-safe; to be called only by worker. /// 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. /// Run network. Not thread-safe; to be called only by worker.
virtual void doWork(); virtual void doWork();
/// Shutdown network. Not thread-safe; to be called only by worker. /// Shutdown network. Not thread-safe; to be called only by worker.
virtual void doneWorking(); virtual void doneWorking();
@ -191,14 +196,14 @@ private:
static KeyPair networkAlias(bytesConstRef _b); static KeyPair networkAlias(bytesConstRef _b);
bytes m_restoreNetwork; ///< Set by constructor and used to set Host key and restore network peers & nodes. 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. bool m_run = false; ///< Whether network is running.
std::mutex x_runTimer; ///< Start/stop mutex. std::mutex x_runTimer; ///< Start/stop mutex.
std::string m_clientVersion; ///< Our version string. std::string m_clientVersion; ///< Our version string.
NetworkPreferences m_netPrefs; ///< Network settings. NetworkPreferences m_netPrefs; ///< Network settings.
/// Interface addresses (private, public) /// Interface addresses (private, public)
std::vector<bi::address> m_ifAddresses; ///< Interface addresses. std::vector<bi::address> m_ifAddresses; ///< Interface addresses.
@ -206,10 +211,10 @@ private:
ba::io_service m_ioService; ///< IOService for network stuff. ba::io_service m_ioService; ///< IOService for network stuff.
bi::tcp::acceptor m_tcp4Acceptor; ///< Listening acceptor. 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. 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. 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&). 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; 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; /// 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; 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()) /// 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 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 std::map<NodeId, std::weak_ptr<Session>> m_sessions;
mutable RecursiveMutex x_sessions; mutable RecursiveMutex x_sessions;
unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. 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::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::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. std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
bool m_accepting = false; bool m_accepting = false;
}; };
} }
} }

27
libp2p/Network.cpp

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

96
libp2p/NodeTable.h

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

6
libp2p/Session.cpp

@ -24,6 +24,7 @@
#include <chrono> #include <chrono>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include "Host.h" #include "Host.h"
#include "Capability.h" #include "Capability.h"
@ -467,6 +468,11 @@ void Session::drop(DisconnectReason _reason)
void Session::disconnect(DisconnectReason _reason) void Session::disconnect(DisconnectReason _reason)
{ {
clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_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()) if (m_socket.is_open())
{ {
RLPStream s; RLPStream s;

3
libp2p/Session.h

@ -27,6 +27,7 @@
#include <set> #include <set>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/RangeMask.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. 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. 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_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? 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. This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
@ -26,6 +26,7 @@
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <array> #include <array>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
@ -49,7 +50,7 @@ public:
UDPDatagram(bi::udp::endpoint const& _ep): locus(_ep) {} UDPDatagram(bi::udp::endpoint const& _ep): locus(_ep) {}
UDPDatagram(bi::udp::endpoint const& _ep, bytes _data): data(_data), locus(_ep) {} UDPDatagram(bi::udp::endpoint const& _ep, bytes _data): data(_data), locus(_ep) {}
bi::udp::endpoint const& endpoint() const { return locus; } bi::udp::endpoint const& endpoint() const { return locus; }
bytes data; bytes data;
protected: protected:
bi::udp::endpoint locus; 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::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 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); static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp);
virtual uint8_t packetType() = 0; virtual uint8_t packetType() = 0;
RLPXDatagramFace(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {} RLPXDatagramFace(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {}
virtual h256 sign(Secret const& _from); virtual h256 sign(Secret const& _from);
@ -97,7 +98,7 @@ struct UDPSocketEvents
virtual void onDisconnected(UDPSocketFace*) {}; virtual void onDisconnected(UDPSocketFace*) {};
virtual void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packetData) = 0; virtual void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packetData) = 0;
}; };
/** /**
* @brief UDP Interface * @brief UDP Interface
* Handler must implement UDPSocketEvents. * Handler must implement UDPSocketEvents.
@ -111,7 +112,7 @@ class UDPSocket: UDPSocketFace, public std::enable_shared_from_this<UDPSocket<Ha
public: public:
enum { maxDatagramSize = MaxDatagramSize }; enum { maxDatagramSize = MaxDatagramSize };
static_assert(maxDatagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes"); 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); }; 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(); } virtual ~UDPSocket() { disconnect(); }
@ -120,32 +121,32 @@ public:
/// Send datagram. /// Send datagram.
bool send(UDPDatagram const& _datagram); bool send(UDPDatagram const& _datagram);
/// Returns if socket is open. /// Returns if socket is open.
bool isOpen() { return !m_closed; } bool isOpen() { return !m_closed; }
/// Disconnect socket. /// Disconnect socket.
void disconnect() { disconnectWithError(boost::asio::error::connection_reset); } void disconnect() { disconnectWithError(boost::asio::error::connection_reset); }
protected: protected:
void doRead(); void doRead();
void doWrite(); void doWrite();
void disconnectWithError(boost::system::error_code _ec); 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_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. std::atomic<bool> m_closed; ///< Connection availability.
UDPSocketEvents& m_host; ///< Interface which owns this socket. UDPSocketEvents& m_host; ///< Interface which owns this socket.
bi::udp::endpoint m_endpoint; ///< Endpoint which we listen to. bi::udp::endpoint m_endpoint; ///< Endpoint which we listen to.
Mutex x_sendQ; Mutex x_sendQ;
std::deque<UDPDatagram> m_sendQ; ///< Queue for egress data. std::deque<UDPDatagram> m_sendQ; ///< Queue for egress data.
std::array<byte, maxDatagramSize> m_recvData; ///< Buffer for ingress data. std::array<byte, maxDatagramSize> m_recvData; ///< Buffer for ingress data.
bi::udp::endpoint m_recvEndpoint; ///< Endpoint data was received from. bi::udp::endpoint m_recvEndpoint; ///< Endpoint data was received from.
bi::udp::socket m_socket; ///< Boost asio udp socket. bi::udp::socket m_socket; ///< Boost asio udp socket.
Mutex x_socketError; ///< Mutex for error which can be set from host or IO thread. 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. 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; bool expect = false;
if (!m_started.compare_exchange_strong(expect, true)) if (!m_started.compare_exchange_strong(expect, true))
return; return;
m_socket.open(bi::udp::v4()); m_socket.open(bi::udp::v4());
m_socket.bind(m_endpoint); m_socket.bind(m_endpoint);
// clear write queue so reconnect doesn't send stale messages // clear write queue so reconnect doesn't send stale messages
Guard l(x_sendQ); Guard l(x_sendQ);
m_sendQ.clear(); m_sendQ.clear();
m_closed = false; m_closed = false;
doRead(); doRead();
} }
template <typename Handler, unsigned MaxDatagramSize> template <typename Handler, unsigned MaxDatagramSize>
bool UDPSocket<Handler, MaxDatagramSize>::send(UDPDatagram const& _datagram) bool UDPSocket<Handler, MaxDatagramSize>::send(UDPDatagram const& _datagram)
{ {
if (m_closed) if (m_closed)
return false; return false;
Guard l(x_sendQ); Guard l(x_sendQ);
m_sendQ.push_back(_datagram); m_sendQ.push_back(_datagram);
if (m_sendQ.size() == 1) if (m_sendQ.size() == 1)
doWrite(); doWrite();
return true; return true;
} }
@ -187,7 +188,7 @@ void UDPSocket<Handler, MaxDatagramSize>::doRead()
{ {
if (m_closed) if (m_closed)
return; return;
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this()); 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) 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(); doRead();
}); });
} }
template <typename Handler, unsigned MaxDatagramSize> template <typename Handler, unsigned MaxDatagramSize>
void UDPSocket<Handler, MaxDatagramSize>::doWrite() void UDPSocket<Handler, MaxDatagramSize>::doWrite()
{ {
if (m_closed) if (m_closed)
return; return;
const UDPDatagram& datagram = m_sendQ[0]; const UDPDatagram& datagram = m_sendQ[0];
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this()); 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) 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; bool expected = true;
if (!m_started.compare_exchange_strong(expected, false)) if (!m_started.compare_exchange_strong(expected, false))
return; return;
// set m_closed to true to prevent undeliverable egress messages // set m_closed to true to prevent undeliverable egress messages
bool wasClosed = m_closed; bool wasClosed = m_closed;
m_closed = true; m_closed = true;
// close sockets // close sockets
boost::system::error_code ec; boost::system::error_code ec;
m_socket.shutdown(bi::udp::socket::shutdown_both, 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); 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} evmcore)
target_link_libraries(${EXECUTABLE} devcore) 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} ) 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} devcore)
target_link_libraries(${EXECUTABLE} devcrypto) 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} ) 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. // We do not check the calldata size, everything is zero-padded.
unsigned offset(CompilerUtils::dataStartOffset); unsigned offset(CompilerUtils::dataStartOffset);
bool const c_padToWords = true;
unsigned dynamicParameterCount = 0; bigint parameterHeadEnd = offset;
for (TypePointer const& type: _typeParameters) for (TypePointer const& type: _typeParameters)
if (type->isDynamicallySized()) parameterHeadEnd += type->isDynamicallySized() ? 32 :
dynamicParameterCount++; CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
offset += dynamicParameterCount * 32; solAssert(parameterHeadEnd <= numeric_limits<unsigned>::max(), "Arguments too large.");
unsigned currentDynamicParameter = 0;
unsigned stackHeightOfPreviousDynamicArgument = 0;
ArrayType const* previousDynamicType = nullptr;
for (TypePointer const& type: _typeParameters) for (TypePointer const& type: _typeParameters)
if (type->isDynamicallySized()) {
switch (type->getCategory())
{ {
// value on stack: [calldata_offset] (only if we are already in dynamic mode) case Type::Category::Array:
if (currentDynamicParameter == 0) if (type->isDynamicallySized())
// switch from static to dynamic {
// 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); m_context << u256(offset);
// retrieve length offset += CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
CompilerUtils(m_context).loadFromMemory( }
CompilerUtils::dataStartOffset + currentDynamicParameter * 32, break;
IntegerType(256), !_fromMemory, c_padToWords); default:
// stack: offset length solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString());
// add 32-byte padding to copy of length offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, true);
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
} }
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) 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)); m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
else else
// send all gas except for the 21 needed to execute "SUB" and "CALL" // 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 << u256(_functionType.valueSet() ? 6741 : 41) << eth::Instruction::GAS << eth::Instruction::SUB;
m_context << eth::Instruction::CALL m_context << eth::Instruction::CALL;
<< eth::Instruction::POP; // @todo do not ignore failure indicator auto tag = m_context.appendConditionalJump();
m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.
if (_functionType.valueSet()) if (_functionType.valueSet())
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
if (_functionType.gasSet()) if (_functionType.gasSet())
@ -999,10 +1000,12 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true); CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true);
} }
void ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expression const>> const& _arguments, void ExpressionCompiler::appendArgumentsCopyToMemory(
TypePointers const& _types, vector<ASTPointer<Expression const>> const& _arguments,
bool _padToWordBoundaries, TypePointers const& _types,
bool _padExceptionIfFourBytes) bool _padToWordBoundaries,
bool _padExceptionIfFourBytes
)
{ {
solAssert(_types.empty() || _types.size() == _arguments.size(), ""); solAssert(_types.empty() || _types.size() == _arguments.size(), "");
for (size_t i = 0; i < _arguments.size(); ++i) for (size_t i = 0; i < _arguments.size(); ++i)

1
libsolidity/Token.h

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

13
libsolidity/Types.cpp

@ -570,6 +570,15 @@ bool ArrayType::operator==(Type const& _other) const
return isDynamicallySized() || getLength() == other.getLength(); 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 u256 ArrayType::getStorageSize() const
{ {
if (isDynamicallySized()) if (isDynamicallySized())
@ -586,8 +595,8 @@ u256 ArrayType::getStorageSize() const
unsigned ArrayType::getSizeOnStack() const unsigned ArrayType::getSizeOnStack() const
{ {
if (m_location == Location::CallData) if (m_location == Location::CallData)
// offset, length (stack top) // offset [length] (stack top)
return 2; return 1 + (isDynamicallySized() ? 1 : 0);
else else
// offset // offset
return 1; return 1;

3
libsolidity/Types.h

@ -30,6 +30,7 @@
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
#include <libsolidity/ASTForward.h> #include <libsolidity/ASTForward.h>
#include <libsolidity/Token.h> #include <libsolidity/Token.h>
#include <libdevcore/UndefMacros.h>
namespace dev namespace dev
{ {
@ -67,7 +68,6 @@ private:
MemberMap m_memberTypes; MemberMap m_memberTypes;
}; };
/** /**
* Abstract base class that forms the root of the type hierarchy. * 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 bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override; virtual bool operator==(const Type& _other) const override;
virtual unsigned getCalldataEncodedSize() const override;
virtual bool isDynamicallySized() const { return m_hasDynamicLength; } virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
virtual u256 getStorageSize() const override; virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() 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(${MHD_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE web3jsonrpc) set(EXECUTABLE web3jsonrpc)
@ -52,7 +53,7 @@ if (ETH_JSON_RPC_STUB)
add_dependencies(${EXECUTABLE} jsonrpcstub) add_dependencies(${EXECUTABLE} jsonrpcstub)
endif() 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

3
libweb3jsonrpc/WebThreeStubServer.cpp

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

10
libweb3jsonrpc/WebThreeStubServerBase.cpp

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

3
libwebthree/CMakeLists.txt

@ -13,6 +13,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE webthree) set(EXECUTABLE webthree)
@ -35,6 +36,6 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} secp256k1) 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

14
libwebthree/WebThree.cpp

@ -23,7 +23,9 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libp2p/Host.h> #include <libp2p/Host.h>
#include <libethereum/Defaults.h> #include <libethereum/Defaults.h>
@ -35,15 +37,21 @@ using namespace dev::p2p;
using namespace dev::eth; using namespace dev::eth;
using namespace dev::shh; 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_clientVersion(_clientVersion),
m_net(_clientVersion, _n, _network) m_net(_clientVersion, _n, _network)
{ {
if (_dbPath.size()) if (_dbPath.size())
Defaults::setDBPath(_dbPath); Defaults::setDBPath(_dbPath);
if (_interfaces.count("eth")) 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")) if (_interfaces.count("shh"))
m_whisper = m_net.registerCapability<WhisperHost>(new WhisperHost); m_whisper = m_net.registerCapability<WhisperHost>(new WhisperHost);

16
libwebthree/WebThree.h

@ -25,7 +25,11 @@
#include <mutex> #include <mutex>
#include <list> #include <list>
#include <atomic> #include <atomic>
// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
@ -103,7 +107,15 @@ class WebThreeDirect : public WebThreeNetworkFace
public: public:
/// Constructor for private instance. If there is already another process on the machine using @a _dbPath, then this will throw an exception. /// 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*. /// 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. /// Destructor.
~WebThreeDirect(); ~WebThreeDirect();
@ -152,7 +164,7 @@ public:
/// Stop the network subsystem. /// Stop the network subsystem.
void stopNetwork() override { m_net.stop(); } void stopNetwork() override { m_net.stop(); }
/// Is network working? there may not be any peers yet. /// Is network working? there may not be any peers yet.
bool isNetworkStarted() const override { return m_net.isStarted(); } 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(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE whisper) set(EXECUTABLE whisper)
@ -32,5 +33,5 @@ target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} p2p)
target_link_libraries(${EXECUTABLE} secp256k1) 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} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

1
libwhisper/Common.h

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

1
libwhisper/Interface.h

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

1
libwhisper/Message.h

@ -26,6 +26,7 @@
#include <set> #include <set>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcrypto/Common.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()); cnote << this << ": inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data());
if (_m.expiry() <= time(0)) if (_m.expiry() <= (unsigned)time(0))
return; return;
auto h = _m.sha3(); auto h = _m.sha3();
@ -171,7 +171,7 @@ void WhisperHost::cleanup()
{ {
// remove old messages. // remove old messages.
// should be called every now and again. // should be called every now and again.
auto now = time(0); unsigned now = (unsigned)time(0);
WriteGuard l(x_messages); WriteGuard l(x_messages);
for (auto it = m_expiryQueue.begin(); it != m_expiryQueue.end() && it->first <= now; it = m_expiryQueue.erase(it)) for (auto it = m_expiryQueue.begin(); it != m_expiryQueue.end() && it->first <= now; it = m_expiryQueue.erase(it))
m_messages.erase(it->second); m_messages.erase(it->second);

1
libwhisper/WhisperHost.h

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

1
libwhisper/WhisperPeer.h

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

1
mix/CMakeLists.txt

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

41
mix/ClientModel.cpp

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

11
mix/ClientModel.h

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

3
mix/DebuggingStateWrapper.h

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

3
mix/Extension.cpp

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

22
mix/MixClient.cpp

@ -40,7 +40,7 @@ namespace dev
namespace mix namespace mix
{ {
const Secret c_userAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074"); const Secret c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
const u256 c_mixGenesisDifficulty = (u256) 1 << 4; const u256 c_mixGenesisDifficulty = (u256) 1 << 4;
class MixBlockChain: public dev::eth::BlockChain class MixBlockChain: public dev::eth::BlockChain
@ -62,16 +62,18 @@ public:
}; };
MixClient::MixClient(std::string const& _dbPath): 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() MixClient::~MixClient()
{ {
} }
void MixClient::resetState(u256 _balance) void MixClient::resetState(std::map<Secret, u256> _accounts)
{ {
WriteGuard l(x_state); WriteGuard l(x_state);
Guard fl(m_filterLock); Guard fl(m_filterLock);
@ -81,12 +83,20 @@ void MixClient::resetState(u256 _balance)
m_stateDB = OverlayDB(); m_stateDB = OverlayDB();
TrieDB<Address, MemoryDB> accountState(&m_stateDB); TrieDB<Address, MemoryDB> accountState(&m_stateDB);
accountState.init(); 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); dev::eth::commit(genesisState, static_cast<MemoryDB&>(m_stateDB), accountState);
h256 stateRoot = accountState.root(); h256 stateRoot = accountState.root();
m_bc.reset(); m_bc.reset();
m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); 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_state.sync(bc());
m_startState = m_state; m_startState = m_state;
m_executions.clear(); m_executions.clear();

6
mix/MixClient.h

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

1
mix/QContractDefinition.cpp

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

4
mix/qml/Ether.qml

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

151
mix/qml/StateDialog.qml

@ -1,5 +1,6 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.0 import QtQuick.Window 2.0
import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles 1.3
@ -12,24 +13,24 @@ Window {
id: modalStateDialog id: modalStateDialog
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
width: 520 width: 590
height: 480 height: 480
title: qsTr("Edit State") title: qsTr("Edit State")
visible: false visible: false
color: StateDialogStyle.generic.backgroundColor color: StateDialogStyle.generic.backgroundColor
property alias stateTitle: titleField.text property alias stateTitle: titleField.text
property alias stateBalance: balanceField.value
property alias isDefault: defaultCheckBox.checked property alias isDefault: defaultCheckBox.checked
property int stateIndex property int stateIndex
property var stateTransactions: [] property var stateTransactions: []
property var stateAccounts: []
signal accepted signal accepted
function open(index, item, setDefault) { function open(index, item, setDefault) {
stateIndex = index; stateIndex = index;
stateTitle = item.title; stateTitle = item.title;
balanceField.value = item.balance;
transactionsModel.clear(); transactionsModel.clear();
stateTransactions = []; stateTransactions = [];
var transactions = item.transactions; var transactions = item.transactions;
for (var t = 0; t < transactions.length; t++) { for (var t = 0; t < transactions.length; t++) {
@ -37,6 +38,14 @@ Window {
stateTransactions.push(item.transactions[t]); 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.setX((Screen.width - width) / 2);
modalStateDialog.setY((Screen.height - height) / 2); modalStateDialog.setY((Screen.height - height) / 2);
@ -54,10 +63,11 @@ Window {
function getItem() { function getItem() {
var item = { var item = {
title: stateDialog.stateTitle, title: stateDialog.stateTitle,
balance: stateDialog.stateBalance, transactions: [],
transactions: [] accounts: []
} }
item.transactions = stateTransactions; item.transactions = stateTransactions;
item.accounts = stateAccounts;
return item; return item;
} }
@ -90,15 +100,112 @@ Window {
RowLayout RowLayout
{ {
Layout.fillWidth: true Layout.fillWidth: true
DefaultLabel {
Rectangle
{
Layout.preferredWidth: 75 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 MessageDialog
edit: true {
displayFormattedValue: true 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 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 { ListModel {
id: transactionsModel id: transactionsModel
function editTransaction(index) { function editTransaction(index) {
transactionDialog.stateAccounts = stateAccounts;
transactionDialog.open(index, transactionsModel.get(index)); transactionDialog.open(index, transactionsModel.get(index));
} }
@ -209,6 +327,7 @@ Window {
// https://bugreports.qt-project.org/browse/QTBUG-41327 // 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 // Second call to signal handler would just edit the item that was just created, no harm done
var item = TransactionHelper.defaultTransaction(); var item = TransactionHelper.defaultTransaction();
transactionDialog.stateAccounts = stateAccounts;
transactionDialog.open(transactionsModel.count, item); transactionDialog.open(transactionsModel.count, item);
} }
@ -216,6 +335,16 @@ Window {
stateTransactions.splice(index, 1); stateTransactions.splice(index, 1);
transactionsModel.remove(index); transactionsModel.remove(index);
} }
function isUsed(secret)
{
for (var i in stateTransactions)
{
if (stateTransactions[i].sender === secret)
return true;
}
return false;
}
} }
Component { Component {

59
mix/qml/StateListModel.qml

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

2
mix/qml/StatusPane.qml

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

33
mix/qml/TransactionDialog.qml

@ -25,6 +25,7 @@ Window {
property var itemParams; property var itemParams;
property bool useTransactionDefaultValue: false property bool useTransactionDefaultValue: false
property var qType; property var qType;
property alias stateAccounts: senderComboBox.model
signal accepted; signal accepted;
@ -44,6 +45,8 @@ Window {
rowFunction.visible = true; rowFunction.visible = true;
itemParams = item.parameters !== undefined ? item.parameters : {}; itemParams = item.parameters !== undefined ? item.parameters : {};
if (item.sender)
senderComboBox.select(item.sender);
contractsModel.clear(); contractsModel.clear();
var contractIndex = -1; var contractIndex = -1;
@ -190,6 +193,7 @@ Window {
item.functionId = transactionDialog.functionId; item.functionId = transactionDialog.functionId;
} }
item.sender = senderComboBox.model[senderComboBox.currentIndex].secret;
var orderedQType = []; var orderedQType = [];
for (var p = 0; p < transactionDialog.transactionParams.count; p++) { for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
var parameter = transactionDialog.transactionParams.get(p); var parameter = transactionDialog.transactionParams.get(p);
@ -210,6 +214,35 @@ Window {
id: dialogContent id: dialogContent
anchors.top: parent.top anchors.top: parent.top
spacing: 10 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 RowLayout
{ {
id: rowContract id: rowContract

6
mix/qml/TransactionLog.qml

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

1
neth/CMakeLists.txt

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

2
neth/main.cpp

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

14
secp256k1/CMakeLists.txt

@ -21,6 +21,18 @@ if (APPLE OR UNIX)
endif() endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -DUSE_FIELD_GMP -DUSE_NUM_GMP -DUSE_FIELD_INV_NUM") 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}) 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() else()
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
@ -36,5 +48,5 @@ else()
endif() 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} ) 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) { function sendAmount(uint amount) returns (uint256 bal) {
return h.getBalance.value(amount)(); return h.getBalance.value(amount)();
} }
function outOfGas() returns (bool flagBefore, bool flagAfter, uint myBal) { function outOfGas() returns (bool ret) {
flagBefore = h.getFlag(); h.setFlag.gas(2)(); // should fail due to OOG
h.setFlag.gas(2)(); // should fail due to OOG, return value can be garbage return true;
}
function checkState() returns (bool flagAfter, uint myBal) {
flagAfter = h.getFlag(); flagAfter = h.getFlag();
myBal = this.balance; myBal = this.balance;
} }
@ -1630,7 +1632,8 @@ BOOST_AUTO_TEST_CASE(gas_and_value_basic)
compileAndRun(sourceCode, 20); compileAndRun(sourceCode, 20);
BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5)); BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5));
// call to helper should not succeed but amount should be transferred anyway // 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) BOOST_AUTO_TEST_CASE(value_complex)
@ -2504,11 +2507,11 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete)
compileAndRun(sourceCode); compileAndRun(sourceCode);
string data = "123456789012345678901234567890123"; string data = "123456789012345678901234567890123";
BOOST_CHECK(m_state.storage(m_contractAddress).empty()); 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(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("copy()") == encodeArgs(true)); BOOST_CHECK(callContractFunction("copy()") == encodeArgs(true));
BOOST_CHECK(m_state.storage(m_contractAddress).empty()); 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(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("del()") == encodeArgs(true)); BOOST_CHECK(callContractFunction("del()") == encodeArgs(true));
BOOST_CHECK(m_state.storage(m_contractAddress).empty()); 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); bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13);
string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3)); string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3));
bytes calldata = encodeArgs( bytes calldata = encodeArgs(
u256(innercalldata1.length()), u256(innercalldata2.length()), 12, u256(innercalldata1.length()), u256(innercalldata2.length()), 13,
12, innercalldata1, innercalldata2, 13); innercalldata1, innercalldata2);
BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata) BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata)
== encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length()))); == encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())));
} }

4
test/TestHelper.cpp

@ -23,7 +23,9 @@
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <libevm/VMFactory.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 // export output
m_TestObject["out"] = "0x" + toHex(_output); m_TestObject["out"] = "0x" + toHex(_output);

4
test/TestHelper.h

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

144
test/block.cpp

@ -81,6 +81,76 @@ bytes createBlockRLPFromFields(mObject& _tObj)
return rlpStream.out(); 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) void doBlockTests(json_spirit::mValue& _v, bool _fillin)
{ {
for (auto& i: _v.get_obj()) for (auto& i: _v.get_obj())
@ -214,76 +284,9 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin)
BlockInfo current_BlockHeader = state.info(); BlockInfo current_BlockHeader = state.info();
// overwrite blockheader with (possible wrong) data from "blockheader" in filler; // overwrite blockheader with (possible wrong) data from "blockheader" in filler;
overwriteBlockHeader(o, 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);
}
}
// write block header // write block header
mObject oBlockHeader; mObject oBlockHeader;
oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash);
oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); 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!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!");
//Check transaction list //Check transaction list
Transactions txsFromField; Transactions txsFromField;
for (auto const& txObj: o["transactions"].get_array()) 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); 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() BOOST_AUTO_TEST_SUITE_END()

2
test/createRandomTest.cpp

@ -23,8 +23,10 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>
#include <boost/random.hpp> #include <boost/random.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
#include <json_spirit/json_spirit.h> #include <json_spirit/json_spirit.h>
#include <json_spirit/json_spirit_reader_template.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/test/unit_test.hpp>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/CanonBlockChain.h> #include <libethereum/CanonBlockChain.h>
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>

6
test/genesis.cpp

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

8
test/hexPrefix.cpp

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

37
test/net.cpp

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

146
test/rlp.cpp

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

3
test/state.cpp

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

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

Loading…
Cancel
Save