Browse Source

Merge branch 'p2p' into wip-requirePeer

cl-refactor
subtly 10 years ago
parent
commit
c179f35ac0
  1. 2
      CMakeLists.txt
  2. 292
      abi/main.cpp
  3. 19
      cmake/EthDependencies.cmake
  4. 13
      eth/main.cpp
  5. 35
      ethrpctest/CMakeLists.txt
  6. 129
      ethrpctest/CommandLineInterface.cpp
  7. 46
      ethrpctest/CommandLineInterface.h
  8. 34
      ethrpctest/main.cpp
  9. 4
      evmjit/libevmjit-cpp/Env.cpp
  10. 17
      evmjit/libevmjit/ExecutionEngine.cpp
  11. 100
      libtestutils/BlockChainLoader.cpp
  12. 52
      libtestutils/BlockChainLoader.h
  13. 34
      libtestutils/CMakeLists.txt
  14. 80
      libtestutils/Common.cpp
  15. 44
      libtestutils/Common.h
  16. 32
      libtestutils/FixedClient.cpp
  17. 59
      libtestutils/FixedClient.h
  18. 22
      libtestutils/FixedWebThreeServer.cpp
  19. 57
      libtestutils/FixedWebThreeServer.h
  20. 56
      libtestutils/StateLoader.cpp
  21. 45
      libtestutils/StateLoader.h
  22. 42
      libtestutils/TransientDirectory.cpp
  23. 50
      libtestutils/TransientDirectory.h
  24. 6
      mix/qml/Debugger.qml
  25. 16
      mix/qml/WebCodeEditor.qml
  26. 46
      mix/qml/html/cm/errorannotation.js
  27. 13
      mix/qml/html/cm/solarized.css
  28. 1
      mix/qml/html/codeeditor.html
  29. 73
      mix/qml/html/codeeditor.js
  30. 5
      mix/qml/js/ErrorLocationFormater.js
  31. 1
      mix/web.qrc
  32. 383
      neth/main.cpp

2
CMakeLists.txt

@ -177,6 +177,7 @@ endif()
if (JSONRPC) if (JSONRPC)
add_subdirectory(libweb3jsonrpc) add_subdirectory(libweb3jsonrpc)
add_subdirectory(ethrpctest)
endif() endif()
add_subdirectory(secp256k1) add_subdirectory(secp256k1)
@ -194,6 +195,7 @@ add_subdirectory(libevm)
add_subdirectory(libethereum) add_subdirectory(libethereum)
add_subdirectory(libwebthree) add_subdirectory(libwebthree)
add_subdirectory(libtestutils)
add_subdirectory(test) add_subdirectory(test)
if (NOT JUSTTESTS) if (NOT JUSTTESTS)

292
abi/main.cpp

@ -21,6 +21,7 @@
*/ */
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "../test/JsonSpiritHeaders.h" #include "../test/JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
@ -105,13 +106,45 @@ enum class Base
Fixed Fixed
}; };
static const map<Base, string> s_bases =
{
{ Base::Bytes, "bytes" },
{ Base::Address, "address" },
{ Base::Int, "int" },
{ Base::Uint, "uint" },
{ Base::Fixed, "fixed" }
};
struct ABIType struct ABIType
{ {
Base base = Base::Unknown; Base base = Base::Unknown;
unsigned size = 32; unsigned size = 32;
unsigned ssize = 0; unsigned ssize = 0;
vector<int> dims; vector<int> dims;
string name;
ABIType() = default; ABIType() = default;
ABIType(std::string const& _type, std::string const& _name):
name(_name)
{
string rest;
for (auto const& i: s_bases)
if (boost::algorithm::starts_with(_type, i.second))
{
base = i.first;
rest = _type.substr(i.second.size());
}
if (base == Base::Unknown)
throw InvalidFormat();
boost::regex r("(\\d*)(x(\\d+))?((\\[\\d*\\])*)");
boost::smatch res;
boost::regex_match(rest, res, r);
size = res[1].length() > 0 ? stoi(res[1]) : 0;
ssize = res[3].length() > 0 ? stoi(res[3]) : 0;
boost::regex r2("\\[(\\d*)\\](.*)");
for (rest = res[4]; boost::regex_match(rest, res, r2); rest = res[2])
dims.push_back(!res[1].length() ? -1 : stoi(res[1]));
}
ABIType(std::string const& _s) ABIType(std::string const& _s)
{ {
if (_s.size() < 1) if (_s.size() < 1)
@ -133,13 +166,21 @@ struct ABIType
size = 32; size = 32;
return; return;
} }
if (_s.find_first_of('x') == string::npos) strings d;
size = stoi(_s.substr(1)); boost::algorithm::split(d, _s, boost::is_any_of("*"));
string s = d[0];
if (s.find_first_of('x') == string::npos)
size = stoi(s.substr(1));
else else
{ {
size = stoi(_s.substr(1, _s.find_first_of('x') - 1)); size = stoi(s.substr(1, s.find_first_of('x') - 1));
ssize = stoi(_s.substr(_s.find_first_of('x') + 1)); ssize = stoi(s.substr(s.find_first_of('x') + 1));
} }
for (unsigned i = 1; i < d.size(); ++i)
if (d[i].empty())
dims.push_back(-1);
else
dims.push_back(stoi(d[i]));
} }
string canon() const string canon() const
@ -164,6 +205,23 @@ struct ABIType
void noteDecimalInput() { if (base == Base::Unknown) { base = Base::Uint; size = 32; } } void noteDecimalInput() { if (base == Base::Unknown) { base = Base::Uint; size = 32; } }
}; };
bytes aligned(bytes const& _b, ABIType _t, Format _f, unsigned _length)
{
(void)_t;
bytes ret = _b;
while (ret.size() < _length)
if (_f == Format::Binary)
ret.push_back(0);
else
ret.insert(ret.begin(), 0);
while (ret.size() > _length)
if (_f == Format::Binary)
ret.pop_back();
else
ret.erase(ret.begin());
return ret;
}
tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix, Tristate _typing) tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix, Tristate _typing)
{ {
ABIType type; ABIType type;
@ -185,7 +243,7 @@ tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix
type.noteHexInput(val.size() - 2); type.noteHexInput(val.size() - 2);
return make_tuple(fromHex(val), type, Format::Hex); return make_tuple(fromHex(val), type, Format::Hex);
} }
if (val.substr(0, 1) == ".") if (val.substr(0, 1) == "+")
{ {
type.noteDecimalInput(); type.noteDecimalInput();
return make_tuple(toCompactBigEndian(bigint(val.substr(1))), type, Format::Decimal); return make_tuple(toCompactBigEndian(bigint(val.substr(1))), type, Format::Decimal);
@ -214,6 +272,168 @@ tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix
throw InvalidUserString(); throw InvalidUserString();
} }
struct ABIMethod
{
string name;
vector<ABIType> ins;
vector<ABIType> outs;
bool isConstant = false;
// isolation *IS* documentation.
ABIMethod() = default;
ABIMethod(js::mObject _o)
{
name = _o["name"].get_str();
isConstant = _o["constant"].get_bool();
if (_o.count("inputs"))
for (auto const& i: _o["inputs"].get_array())
{
js::mObject a = i.get_obj();
ins.push_back(ABIType(a["type"].get_str(), a["name"].get_str()));
}
if (_o.count("outputs"))
for (auto const& i: _o["outputs"].get_array())
{
js::mObject a = i.get_obj();
outs.push_back(ABIType(a["type"].get_str(), a["name"].get_str()));
}
}
ABIMethod(string const& _name, vector<ABIType> const& _args)
{
name = _name;
ins = _args;
}
string sig() const
{
string methodArgs;
for (auto const& arg: ins)
methodArgs += (methodArgs.empty() ? "" : ",") + arg.canon();
return name + "(" + methodArgs + ")";
}
FixedHash<4> id() const { return FixedHash<4>(sha3(sig())); }
std::string solidityDeclaration() const
{
ostringstream ss;
ss << "function " << name << "(";
int f = 0;
for (ABIType const& i: ins)
ss << (f++ ? ", " : "") << i.canon() << " " << i.name;
ss << ") ";
if (isConstant)
ss << "constant ";
if (!outs.empty())
{
ss << "returns (";
f = 0;
for (ABIType const& i: outs)
ss << (f ? ", " : "") << i.canon() << " " << i.name;
ss << ")";
}
return ss.str();
}
bytes encode(vector<pair<bytes, Format>> const& _params) const
{
bytes ret = name.empty() ? bytes() : id().asBytes();
unsigned pi = 0;
vector<unsigned> inArity;
for (ABIType const& i: ins)
{
unsigned arity = 1;
for (auto j: i.dims)
if (j == -1)
{
ret += aligned(_params[pi].first, ABIType(), Format::Decimal, 32);
arity *= fromBigEndian<uint>(_params[pi].first);
pi++;
}
else
arity *= j;
inArity.push_back(arity);
}
unsigned ii = 0;
for (ABIType const& i: ins)
{
for (unsigned j = 0; j < inArity[ii]; ++j)
{
ret += aligned(_params[pi].first, i, _params[pi].second, (i.base == Base::Bytes && i.size == 1) ? 1 : 32);
++pi;
}
++ii;
while (ret.size() % 32 != 0)
ret.push_back(0);
}
return ret;
}
};
string canonSig(string const& _name, vector<ABIType> const& _args)
{
string methodArgs;
for (auto const& arg: _args)
methodArgs += (methodArgs.empty() ? "" : ",") + arg.canon();
return _name + "(" + methodArgs + ")";
}
struct UnknownMethod: public Exception {};
struct OverloadedMethod: public Exception {};
class ABI
{
public:
ABI() = default;
ABI(std::string const& _json)
{
js::mValue v;
js::read_string(_json, v);
for (auto const& i: v.get_array())
{
js::mObject o = i.get_obj();
if (o["type"].get_str() != "function")
continue;
ABIMethod m(o);
m_methods[m.id()] = m;
}
}
ABIMethod method(string _nameOrSig, vector<ABIType> const& _args) const
{
auto id = FixedHash<4>(sha3(_nameOrSig));
if (!m_methods.count(id))
id = FixedHash<4>(sha3(canonSig(_nameOrSig, _args)));
if (!m_methods.count(id))
for (auto const& m: m_methods)
if (m.second.name == _nameOrSig)
{
if (m_methods.count(id))
throw OverloadedMethod();
id = m.first;
}
if (m_methods.count(id))
return m_methods.at(id);
throw UnknownMethod();
}
friend ostream& operator<<(ostream& _out, ABI const& _abi);
private:
map<FixedHash<4>, ABIMethod> m_methods;
};
ostream& operator<<(ostream& _out, ABI const& _abi)
{
_out << "contract {" << endl;
for (auto const& i: _abi.m_methods)
_out << " " << i.second.solidityDeclaration() << "; // " << i.first.abridged() << endl;
_out << "}" << endl;
return _out;
}
void userOutput(ostream& _out, bytes const& _data, Encoding _e) void userOutput(ostream& _out, bytes const& _data, Encoding _e)
{ {
switch (_e) switch (_e)
@ -226,20 +446,11 @@ void userOutput(ostream& _out, bytes const& _data, Encoding _e)
} }
} }
bytes aligned(bytes const& _b, ABIType _t, Format _f, unsigned _length) template <unsigned n, class T> vector<typename std::remove_reference<decltype(get<n>(T()))>::type> retrieve(vector<T> const& _t)
{ {
(void)_t; vector<typename std::remove_reference<decltype(get<n>(T()))>::type> ret;
bytes ret = _b; for (T const& i: _t)
while (ret.size() < _length) ret.push_back(get<n>(i));
if (_f == Format::Binary)
ret.push_back(0);
else
ret.insert(ret.begin(), 0);
while (ret.size() > _length)
if (_f == Format::Binary)
ret.pop_back();
else
ret.erase(ret.begin());
return ret; return ret;
} }
@ -255,7 +466,8 @@ int main(int argc, char** argv)
bool clearNulls = false; bool clearNulls = false;
bool verbose = false; bool verbose = false;
int outputIndex = -1; int outputIndex = -1;
vector<tuple<bytes, ABIType, Format>> args; vector<pair<bytes, Format>> params;
vector<ABIType> args;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
{ {
@ -297,38 +509,40 @@ int main(int argc, char** argv)
else if (method.empty()) else if (method.empty())
method = arg; method = arg;
else else
args.push_back(fromUser(arg, prefix, typePrefix)); {
auto u = fromUser(arg, prefix, typePrefix);
args.push_back(get<1>(u));
params.push_back(make_pair(get<0>(u), get<2>(u)));
}
} }
string abi; string abiData;
if (abiFile == "--") if (abiFile == "--")
for (int i = cin.get(); i != -1; i = cin.get()) for (int i = cin.get(); i != -1; i = cin.get())
abi.push_back((char)i); abiData.push_back((char)i);
else if (!abiFile.empty()) else if (!abiFile.empty())
abi = contentsString(abiFile); abiData = contentsString(abiFile);
if (mode == Mode::Encode) if (mode == Mode::Encode)
{ {
bytes ret; ABIMethod m;
if (abi.empty()) if (abiData.empty())
m = ABIMethod(method, args);
else
{ {
if (!method.empty()) ABI abi(abiData);
if (verbose)
cerr << "ABI:" << endl << abi;
try {
m = abi.method(method, args);
}
catch(...)
{ {
string methodArgs; cerr << "Unknown method in ABI." << endl;
for (auto const& arg: args) exit(-1);
methodArgs += (methodArgs.empty() ? "" : ",") + get<1>(arg).canon();
ret = FixedHash<4>(sha3(method + "(" + methodArgs + ")")).asBytes();
if (verbose)
cerr << "Method signature: " << (method + "(" + methodArgs + ")") << endl;
} }
for (tuple<bytes, ABIType, Format> const& arg: args)
ret += aligned(get<0>(arg), get<1>(arg), get<2>(arg), 32);
}
else
{
// TODO: read abi.
} }
userOutput(cout, ret, encoding); userOutput(cout, m.encode(params), encoding);
} }
else if (mode == Mode::Decode) else if (mode == Mode::Decode)
{ {

19
cmake/EthDependencies.cmake

@ -117,14 +117,17 @@ if (NOT HEADLESS)
# find all of the Qt packages # find all of the Qt packages
# remember to use 'Qt' instead of 'QT', cause unix is case sensitive # remember to use 'Qt' instead of 'QT', cause unix is case sensitive
# TODO make headless client optional # TODO make headless client optional
find_package (Qt5Core REQUIRED)
find_package (Qt5Gui REQUIRED) set (ETH_QT_VERSION 5.4)
find_package (Qt5Quick REQUIRED)
find_package (Qt5Qml REQUIRED) find_package (Qt5Core ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Network REQUIRED) find_package (Qt5Gui ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Widgets REQUIRED) find_package (Qt5Quick ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5WebEngine REQUIRED) find_package (Qt5Qml ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5WebEngineWidgets REQUIRED) find_package (Qt5Network ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Widgets ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5WebEngine ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5WebEngineWidgets ${ETH_QT_VERSION} REQUIRED)
# we need to find path to macdeployqt on mac # we need to find path to macdeployqt on mac
if (APPLE) if (APPLE)

13
eth/main.cpp

@ -77,7 +77,6 @@ void interactiveHelp()
<< " setetherprice <p> Resets the ether price." << endl << " setetherprice <p> Resets the ether price." << endl
<< " setpriority <p> Resets the transaction priority." << endl << " setpriority <p> Resets the transaction priority." << endl
<< " minestart Starts mining." << endl << " minestart Starts mining." << endl
<< " minestart Starts mining." << endl
<< " minestop Stops mining." << endl << " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl << " mineforce <enable> Forces mining, even when there are no transactions." << endl
<< " address Gives the current address." << endl << " address Gives the current address." << endl
@ -88,12 +87,14 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl << " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl << " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl << " peers List the peers that are connected" << endl
#if ETH_FATDB
<< " listaccounts List the accounts on the network." << endl << " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl << " listcontracts List the contracts on the network." << endl
<< " setsecret <secret> Set the secret to the hex secret key." <<endl #endif
<< " setaddress <addr> Set the coinbase (mining payout) address." <<endl << " setsecret <secret> Set the secret to the hex secret key." << endl
<< " exportconfig <path> Export the config (.RLP) to the path provided." <<endl << " setaddress <addr> Set the coinbase (mining payout) address." << endl
<< " importconfig <path> Import the config (.RLP) from the path provided." <<endl << " exportconfig <path> Export the config (.RLP) to the path provided." << endl
<< " importconfig <path> Import the config (.RLP) from the path provided." << endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl << " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " dumptrace <block> <index> <filename> <format> Dumps a transaction trace" << endl << "to <filename>. <format> should be one of pretty, standard, standard+." << endl << " dumptrace <block> <index> <filename> <format> Dumps a transaction trace" << endl << "to <filename>. <format> should be one of pretty, standard, standard+." << endl
<< " dumpreceipt <block> <index> Dumps a transation receipt." << endl << " dumpreceipt <block> <index> Dumps a transation receipt." << endl
@ -685,6 +686,7 @@ int main(int argc, char** argv)
else else
cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
} }
#if ETH_FATDB
else if (c && cmd == "listcontracts") else if (c && cmd == "listcontracts")
{ {
auto acs =c->addresses(); auto acs =c->addresses();
@ -707,6 +709,7 @@ int main(int argc, char** argv)
cout << ss << endl; cout << ss << endl;
} }
} }
#endif
else if (c && cmd == "send") else if (c && cmd == "send")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)

35
ethrpctest/CMakeLists.txt

@ -0,0 +1,35 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
set(EXECUTABLE ethrpctest)
file(GLOB HEADERS "*.h")
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
if (READLINE_FOUND)
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
endif()
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_PROGRAM_OPTIONS_LIBRARIES})
target_link_libraries(${EXECUTABLE} testutils)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin )

129
ethrpctest/CommandLineInterface.cpp

@ -0,0 +1,129 @@
/*
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 CommandLineInterface.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <string>
#include <iostream>
#include <fstream>
#include <csignal>
#include <thread>
#include <boost/filesystem.hpp>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <libtestutils/Common.h>
#include <libtestutils/BlockChainLoader.h>
#include <libtestutils/FixedClient.h>
#include <libtestutils/FixedWebThreeServer.h>
#include "CommandLineInterface.h"
#include "BuildInfo.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
namespace po = boost::program_options;
bool CommandLineInterface::parseArguments(int argc, char** argv)
{
// Declare the supported options.
po::options_description desc("Allowed options");
desc.add_options()
("help", "Show help message and exit")
("json", po::value<vector<string>>()->required(), "input file")
("test", po::value<vector<string>>()->required(), "test case name");
// All positional options should be interpreted as input files
po::positional_options_description p;
// parse the compiler arguments
try
{
po::store(po::command_line_parser(argc, argv).options(desc).positional(p).allow_unregistered().run(), m_args);
if (m_args.count("help"))
{
cout << desc;
return false;
}
po::notify(m_args);
}
catch (po::error const& _exception)
{
cout << _exception.what() << endl;
return false;
}
return true;
}
bool CommandLineInterface::processInput()
{
string infile = m_args["json"].as<vector<string>>()[0];
auto path = boost::filesystem::path(infile);
if (!boost::filesystem::exists(path))
{
cout << "Non existant input file \"" << infile << "\"" << endl;
return false;
}
string test = m_args["test"].as<vector<string>>()[0];
Json::Value j = dev::test::loadJsonFromFile(path.string());
if (j[test].empty())
{
cout << "Non existant test case \"" << infile << "\"" << endl;
return false;
}
if (!j[test].isObject())
{
cout << "Incorrect JSON file \"" << infile << "\"" << endl;
return false;
}
m_json = j[test];
return true;
}
bool g_exit = false;
void sighandler(int)
{
g_exit = true;
}
void CommandLineInterface::actOnInput()
{
BlockChainLoader bcl(m_json);
FixedClient client(bcl.bc(), bcl.state());
unique_ptr<FixedWebThreeServer> jsonrpcServer;
auto server = new jsonrpc::HttpServer(8080, "", "", 2);
jsonrpcServer.reset(new FixedWebThreeServer(*server, {}, &client));
jsonrpcServer->StartListening();
signal(SIGABRT, &sighandler);
signal(SIGTERM, &sighandler);
signal(SIGINT, &sighandler);
while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
}

46
ethrpctest/CommandLineInterface.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/>.
*/
/** CommandLineInterface.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <json/json.h>
#include <boost/program_options.hpp>
class CommandLineInterface
{
public:
CommandLineInterface() {}
/// Parse command line arguments and return false if we should not continue
bool parseArguments(int argc, char** argv);
/// Parse input file and check if test exists
bool processInput();
/// Start FixedJsonRpcServer
void actOnInput();
private:
/// Compiler arguments variable map
boost::program_options::variables_map m_args;
/// loaded json test case
Json::Value m_json;
};

34
ethrpctest/main.cpp

@ -0,0 +1,34 @@
/*
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/>.
*/
/** main.cpp
* @author Marek Kotewicz <c@ethdev.com>
* @date 2015
*/
#include "CommandLineInterface.h"
int main(int argc, char** argv)
{
CommandLineInterface cli;
if (!cli.parseArguments(argc, argv))
return 1;
if (!cli.processInput())
return 1;
cli.actOnInput();
return 0;
}

4
evmjit/libevmjit-cpp/Env.cpp

@ -52,7 +52,6 @@ extern "C"
auto endowment = llvm2eth(*_endowment); auto endowment = llvm2eth(*_endowment);
if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024)
{ {
_env->subBalance(endowment);
u256 gas = *io_gas; u256 gas = *io_gas;
h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight);
*io_gas = static_cast<int64_t>(gas); *io_gas = static_cast<int64_t>(gas);
@ -89,10 +88,7 @@ extern "C"
auto ret = false; auto ret = false;
auto callGas = u256{_callGas}; auto callGas = u256{_callGas};
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
{
_env->subBalance(value);
ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress); ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress);
}
*io_gas += static_cast<int64_t>(callGas); // it is never more than initial _callGas *io_gas += static_cast<int64_t>(callGas); // it is never more than initial _callGas
return ret; return ret;

17
evmjit/libevmjit/ExecutionEngine.cpp

@ -4,6 +4,8 @@
#include <mutex> #include <mutex>
#include <iostream> #include <iostream>
#include <unordered_map> #include <unordered_map>
#include <cstdlib>
#include <cstring>
#include "preprocessor/llvm_includes_start.h" #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
@ -82,7 +84,20 @@ void parseOptions()
{ {
static llvm::llvm_shutdown_obj shutdownObj{}; static llvm::llvm_shutdown_obj shutdownObj{};
cl::AddExtraVersionPrinter(printVersion); cl::AddExtraVersionPrinter(printVersion);
cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); //cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler");
// FIXME: LLVM workaround:
// Manually select instruction scheduler other than "source".
// "source" scheduler has a bug: http://llvm.org/bugs/show_bug.cgi?id=22304
auto envLine = std::getenv("EVMJIT");
auto commandLine = std::string{"evmjit "} + (envLine ? envLine : "") + " -pre-RA-sched=list-burr\0";
static const auto c_maxArgs = 20;
char const* argv[c_maxArgs] = {nullptr, };
auto arg = std::strtok(&*commandLine.begin(), " ");
auto i = 0;
for (; i < c_maxArgs && arg; ++i, arg = std::strtok(nullptr, " "))
argv[i] = arg;
cl::ParseCommandLineOptions(i, argv, "Ethereum EVM JIT Compiler");
} }
} }

100
libtestutils/BlockChainLoader.cpp

@ -0,0 +1,100 @@
/*
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 BlockChainLoader.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "BlockChainLoader.h"
#include "StateLoader.h"
#include "Common.h"
using namespace std;
using namespace dev;
using namespace dev::test;
using namespace dev::eth;
namespace dev
{
namespace test
{
dev::eth::BlockInfo toBlockInfo(Json::Value const& _json);
bytes toGenesisBlock(Json::Value const& _json);
}
}
dev::eth::BlockInfo dev::test::toBlockInfo(Json::Value const& _json)
{
RLPStream rlpStream;
auto size = _json.getMemberNames().size();
rlpStream.appendList(_json["hash"].empty() ? size : (size - 1));
rlpStream << fromHex(_json["parentHash"].asString());
rlpStream << fromHex(_json["uncleHash"].asString());
rlpStream << fromHex(_json["coinbase"].asString());
rlpStream << fromHex(_json["stateRoot"].asString());
rlpStream << fromHex(_json["transactionsTrie"].asString());
rlpStream << fromHex(_json["receiptTrie"].asString());
rlpStream << fromHex(_json["bloom"].asString());
rlpStream << bigint(_json["difficulty"].asString());
rlpStream << bigint(_json["number"].asString());
rlpStream << bigint(_json["gasLimit"].asString());
rlpStream << bigint(_json["gasUsed"].asString());
rlpStream << bigint(_json["timestamp"].asString());
rlpStream << fromHex(_json["extraData"].asString());
rlpStream << fromHex(_json["mixHash"].asString());
rlpStream << fromHex(_json["nonce"].asString());
BlockInfo result;
RLP rlp(rlpStream.out());
result.populateFromHeader(rlp, IgnoreNonce);
return result;
}
bytes dev::test::toGenesisBlock(Json::Value const& _json)
{
BlockInfo bi = toBlockInfo(_json);
RLPStream rlpStream;
bi.streamRLP(rlpStream, WithNonce);
RLPStream fullStream(3);
fullStream.appendRaw(rlpStream.out());
fullStream.appendRaw(RLPEmptyList);
fullStream.appendRaw(RLPEmptyList);
bi.verifyInternals(&fullStream.out());
return fullStream.out();
}
BlockChainLoader::BlockChainLoader(Json::Value const& _json)
{
// load pre state
StateLoader sl(_json["pre"]);
m_state = sl.state();
// load genesisBlock
m_bc.reset(new BlockChain(toGenesisBlock(_json["genesisBlockHeader"]), m_dir.path(), true));
// load blocks
for (auto const& block: _json["blocks"])
{
bytes rlp = fromHex(block["rlp"].asString());
m_bc->import(rlp, m_state.db());
}
// sync state
m_state.sync(*m_bc);
}

52
libtestutils/BlockChainLoader.h

@ -0,0 +1,52 @@
/*
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 BlockChainLoader.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <string>
#include <json/json.h>
#include <libethereum/BlockChain.h>
#include <libethereum/State.h>
#include "TransientDirectory.h"
namespace dev
{
namespace test
{
/**
* @brief Should be used to load test blockchain from json file
* Loads the blockchain from json, creates temporary directory to store it, removes the directory on dealloc
*/
class BlockChainLoader
{
public:
BlockChainLoader(Json::Value const& _json);
eth::BlockChain const& bc() const { return *m_bc; }
eth::State const& state() const { return m_state; }
private:
TransientDirectory m_dir;
std::auto_ptr<eth::BlockChain> m_bc;
eth::State m_state;
};
}
}

34
libtestutils/CMakeLists.txt

@ -0,0 +1,34 @@
cmake_policy(SET CMP0015 NEW)
# this policy was introduced in cmake 3.0
# remove if, once 3.0 will be used on unix
if (${CMAKE_MAJOR_VERSION} GREATER 2)
# old policy do not use MACOSX_RPATH
cmake_policy(SET CMP0042 OLD)
endif()
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE testutils)
file(GLOB HEADERS "*.h")
if (ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

80
libtestutils/Common.cpp

@ -0,0 +1,80 @@
/*
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 Common.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <random>
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/FileSystem.h>
#include "Common.h"
using namespace std;
using namespace dev;
using namespace dev::test;
std::string dev::test::getTestPath()
{
string testPath;
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
if (ptestPath == NULL)
{
ctest << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
return testPath;
}
int dev::test::randomNumber()
{
static std::mt19937 randomGenerator(time(0));
randomGenerator.seed(std::random_device()());
return std::uniform_int_distribution<int>(1)(randomGenerator);
}
Json::Value dev::test::loadJsonFromFile(std::string const& _path)
{
Json::Reader reader;
Json::Value result;
string s = asString(dev::contents(_path));
if (!s.length())
ctest << "Contents of " + _path + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?";
else
ctest << "FIXTURE: loaded test from file: " << _path;
reader.parse(s, result);
return result;
}
std::string dev::test::toTestFilePath(std::string const& _filename)
{
return getTestPath() + "/" + _filename + ".json";
}
std::string dev::test::getRandomPath()
{
std::stringstream stream;
stream << getDataDir() << "/EthereumTests/" << randomNumber();
return stream.str();
}

44
libtestutils/Common.h

@ -0,0 +1,44 @@
/*
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 Common.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <string>
#include <json/json.h>
#include <libdevcore/Log.h>
namespace dev
{
namespace test
{
struct TestChannel: public LogChannel { static const char* name() { return "TEST"; } };
#define ctest dev::LogOutputStream<dev::test::TestChannel, true>()
std::string getTestPath();
int randomNumber();
Json::Value loadJsonFromFile(std::string const& _path);
std::string toTestFilePath(std::string const& _filename);
std::string getRandomPath();
}
}

32
libtestutils/FixedClient.cpp

@ -0,0 +1,32 @@
/*
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 FixedClient.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "FixedClient.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
eth::State FixedClient::asOf(h256 const& _h) const
{
ReadGuard l(x_stateDB);
return State(m_state.db(), bc(), _h);
}

59
libtestutils/FixedClient.h

@ -0,0 +1,59 @@
/*
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 FixedClient.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <libethereum/ClientBase.h>
#include <libethereum/BlockChain.h>
#include <libethereum/State.h>
namespace dev
{
namespace test
{
/**
* @brief mvp implementation of ClientBase
* Doesn't support mining interface
*/
class FixedClient: public dev::eth::ClientBase
{
public:
FixedClient(eth::BlockChain const& _bc, eth::State _state) : m_bc(_bc), m_state(_state) {}
virtual ~FixedClient() {}
// stub
virtual void flushTransactions() override {}
virtual eth::BlockChain const& bc() const override { return m_bc; }
using ClientBase::asOf;
virtual eth::State asOf(h256 const& _h) const override;
virtual eth::State preMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual eth::State postMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual void prepareForTransaction() override {}
private:
eth::BlockChain const& m_bc;
eth::State m_state;
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
};
}
}

22
libtestutils/FixedWebThreeServer.cpp

@ -0,0 +1,22 @@
/*
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 FixedWebThreeStubServer.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "FixedWebThreeServer.h"

57
libtestutils/FixedWebThreeServer.h

@ -0,0 +1,57 @@
/*
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 FixedWebThreeStubServer.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <libdevcore/Exceptions.h>
#include <libweb3jsonrpc/WebThreeStubServerBase.h>
/**
* @brief dummy JSON-RPC api implementation
* Should be used for test purposes only
* Supports eth && db interfaces
* Doesn't support shh && net interfaces
*/
class FixedWebThreeServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace
{
public:
FixedWebThreeServer(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client): WebThreeStubServerBase(_conn, _accounts), m_client(_client) {};
private:
dev::eth::Interface* client() override { return m_client; }
std::shared_ptr<dev::shh::Interface> face() override { BOOST_THROW_EXCEPTION(dev::InterfaceNotSupported("dev::shh::Interface")); }
dev::WebThreeNetworkFace* network() override { BOOST_THROW_EXCEPTION(dev::InterfaceNotSupported("dev::WebThreeNetworkFace")); }
dev::WebThreeStubDatabaseFace* db() override { return this; }
std::string get(std::string const& _name, std::string const& _key) override
{
std::string k(_name + "/" + _key);
return m_db[k];
}
void put(std::string const& _name, std::string const& _key, std::string const& _value) override
{
std::string k(_name + "/" + _key);
m_db[k] = _value;
}
private:
dev::eth::Interface* m_client;
std::map<std::string, std::string> m_db;
};

56
libtestutils/StateLoader.cpp

@ -0,0 +1,56 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file StateLoader.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "StateLoader.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
StateLoader::StateLoader(Json::Value const& _json) : m_state(Address(), OverlayDB(), BaseState::Empty)
{
for (string const& name: _json.getMemberNames())
{
Json::Value o = _json[name];
Address address = Address(name);
bytes code = fromHex(o["code"].asString().substr(2));
if (code.size())
{
m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::ContractConception);
m_state.m_cache[address].setCode(code);
}
else
m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::NormalCreation);
for (string const& j: o["storage"].getMemberNames())
m_state.setStorage(address, u256(j), u256(o["storage"][j].asString()));
for (auto i = 0; i < u256(o["nonce"].asString()); ++i)
m_state.noteSending(address);
m_state.ensureCached(address, false, false);
}
m_state.commit();
}

45
libtestutils/StateLoader.h

@ -0,0 +1,45 @@
/*
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 StateLoader.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <json/json.h>
#include <libethereum/State.h>
namespace dev
{
namespace test
{
/**
* @brief Friend of State, loads State from given JSON object
*/
class StateLoader
{
public:
StateLoader(Json::Value const& _json);
eth::State const& state() const { return m_state; }
private:
eth::State m_state;
};
}
}

42
libtestutils/TransientDirectory.cpp

@ -0,0 +1,42 @@
/*
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 TransientDirectory.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <boost/filesystem.hpp>
#include <libdevcore/Exceptions.h>
#include "TransientDirectory.h"
using namespace std;
using namespace dev;
using namespace dev::test;
TransientDirectory::TransientDirectory(std::string const& _path) : m_path(_path)
{
// we never ever want to delete a directory (including all its contents) that we did not create ourselves.
if (boost::filesystem::exists(m_path))
BOOST_THROW_EXCEPTION(FileError());
boost::filesystem::create_directories(m_path);
}
TransientDirectory::~TransientDirectory()
{
boost::filesystem::remove_all(m_path);
}

50
libtestutils/TransientDirectory.h

@ -0,0 +1,50 @@
/*
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 TransientDirectory.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <string>
#include "Common.h"
namespace dev
{
namespace test
{
/**
* @brief temporary directory implementation
* It creates temporary directory in the given path. On dealloc it removes the directory
* @throws if the given path already exists, throws an exception
*/
class TransientDirectory
{
public:
TransientDirectory(std::string const& _path = getRandomPath());
~TransientDirectory();
std::string const& path() const { return m_path; }
private:
std::string m_path;
};
}
}

6
mix/qml/Debugger.qml

@ -40,7 +40,7 @@ Rectangle {
var errorInfo = ErrorLocationFormater.extractErrorInfo(compilationErrorMessage, false); var errorInfo = ErrorLocationFormater.extractErrorInfo(compilationErrorMessage, false);
errorLocation.text = errorInfo.errorLocation; errorLocation.text = errorInfo.errorLocation;
errorDetail.text = errorInfo.errorDetail; errorDetail.text = errorInfo.errorDetail;
errorLine.text = errorInfo.errorLine; errorLine.text = errorInfo.line;
} }
function update(data, giveFocus) function update(data, giveFocus)
@ -242,7 +242,6 @@ Rectangle {
height: 30 height: 30
buttonShortcut: "Ctrl+Shift+F11" buttonShortcut: "Ctrl+Shift+F11"
buttonTooltip: qsTr("Step Out Back") buttonTooltip: qsTr("Step Out Back")
visible: false
} }
StepActionImage StepActionImage
@ -315,9 +314,8 @@ Rectangle {
height: 30 height: 30
buttonShortcut: "Ctrl+F5" buttonShortcut: "Ctrl+F5"
buttonTooltip: qsTr("Run Forward") buttonTooltip: qsTr("Run Forward")
visible: false
} }
} }
} }

16
mix/qml/WebCodeEditor.qml

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtWebEngine 1.0 import QtWebEngine 1.0
import QtWebEngine.experimental 1.0 import QtWebEngine.experimental 1.0
import "js/ErrorLocationFormater.js" as ErrorLocationFormater
Item { Item {
signal editorTextChanged signal editorTextChanged
@ -83,7 +84,22 @@ Item {
runJavaScript("getTextChanged()", function(result) { }); runJavaScript("getTextChanged()", function(result) { });
pollTimer.running = true; pollTimer.running = true;
syncClipboard(); syncClipboard();
if (currentMode === "solidity")
{
codeModel.onCompilationComplete.connect(function(){
runJavaScript("compilationComplete()", function(result) { });
});
codeModel.onCompilationError.connect(function(error){
var errorInfo = ErrorLocationFormater.extractErrorInfo(error, false);
if (errorInfo.line && errorInfo.column)
runJavaScript("compilationError('" + errorInfo.line + "', '" + errorInfo.column + "', '" + errorInfo.errorDetail + "')", function(result) { });
else
runJavaScript("compilationComplete()", function(result) { });
});
}
parent.changeGeneration(); parent.changeGeneration();
} }
} }

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

@ -0,0 +1,46 @@
function ErrorAnnotation(editor, line, column, content)
{
this.opened = false;
this.line = line;
this.column = column;
this.content = content.replace("Contract Error:", "");
this.editor = editor;
this.errorMark = null;
this.lineWidget = null;
this.init();
this.open();
}
ErrorAnnotation.prototype.init = function()
{
var separators = [';', ',', '\\\(', '\\\{', '\\\}', '\\\)', ':'];
var errorPart = editor.getLine(this.line).substring(this.column);
var incrMark = this.column + errorPart.split(new RegExp(separators.join('|'), 'g'))[0].length;
if (incrMark === this.column)
incrMark = this.column + 1;
this.errorMark = editor.markText({ line: this.line, ch: this.column }, { line: this.line, ch: incrMark }, { className: "CodeMirror-errorannotation", inclusiveRight: true });
}
ErrorAnnotation.prototype.open = function()
{
var node = document.createElement("div");
node.id = "annotation"
node.innerHTML = this.content;
node.className = "CodeMirror-errorannotation-context";
this.lineWidget = this.editor.addLineWidget(this.errorMark.find().from.line, node, { coverGutter: false });
this.opened = true;
}
ErrorAnnotation.prototype.close = function()
{
this.lineWidget.clear();
this.opened = false;
}
ErrorAnnotation.prototype.destroy = function()
{
if (this.opened)
this.close();
if (this.errorMark)
this.errorMark.clear();
}

13
mix/qml/html/cm/solarized.css

@ -169,3 +169,16 @@ view-port
background: rgba(255, 255, 255, 0.10); background: rgba(255, 255, 255, 0.10);
} }
/* Error annotation */
.CodeMirror-errorannotation {
border-bottom: 1px solid #b58900;
}
.CodeMirror-errorannotation-context {
font-family: monospace;
font-size: small;
color: #586e75;
background: #b58900;
padding: 2px;
}

1
mix/qml/html/codeeditor.html

@ -22,6 +22,7 @@
<script src="cm/javascript-hint.js"></script> <script src="cm/javascript-hint.js"></script>
<script src="cm/anyword-hint.js"></script> <script src="cm/anyword-hint.js"></script>
<script src="cm/closebrackets.js"></script> <script src="cm/closebrackets.js"></script>
<script src="cm/errorannotation.js"></script>
<script src="cm/tern.js"></script> <script src="cm/tern.js"></script>
<script src="cm/acorn.js"></script> <script src="cm/acorn.js"></script>
<script src="cm/acorn_loose.js"></script> <script src="cm/acorn_loose.js"></script>

73
mix/qml/html/codeeditor.js

@ -22,23 +22,23 @@ editor.on("change", function(eMirror, object) {
var mac = /Mac/.test(navigator.platform); var mac = /Mac/.test(navigator.platform);
if (mac === true) { if (mac === true) {
editor.setOption("extraKeys", { editor.setOption("extraKeys", {
"Cmd-V": function(cm) { "Cmd-V": function(cm) {
cm.replaceSelection(clipboard); cm.replaceSelection(clipboard);
}, },
"Cmd-X": function(cm) { "Cmd-X": function(cm) {
window.document.execCommand("cut"); window.document.execCommand("cut");
}, },
"Cmd-C": function(cm) { "Cmd-C": function(cm) {
window.document.execCommand("copy"); window.document.execCommand("copy");
}}); }});
} }
makeMarker = function() { makeMarker = function() {
var marker = document.createElement("div"); var marker = document.createElement("div");
marker.style.color = "#822"; marker.style.color = "#822";
marker.innerHTML = "●"; marker.innerHTML = "●";
return marker; return marker;
}; };
toggleBreakpointLine = function(n) { toggleBreakpointLine = function(n) {
@ -77,9 +77,9 @@ getBreakpoints = function() {
if (line.gutterMarkers && line.gutterMarkers["breakpoints"]) { if (line.gutterMarkers && line.gutterMarkers["breakpoints"]) {
var l = doc.getLineNumber(line); var l = doc.getLineNumber(line);
locations.push({ locations.push({
start: editor.indexFromPos({ line: l, ch: 0}), start: editor.indexFromPos({ line: l, ch: 0}),
end: editor.indexFromPos({ line: l + 1, ch: 0}) end: editor.indexFromPos({ line: l + 1, ch: 0})
});; });;
} }
}); });
return locations; return locations;
@ -116,7 +116,7 @@ setMode = function(mode) {
else if (mode === "solidity") else if (mode === "solidity")
{ {
CodeMirror.commands.autocomplete = function(cm) { CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, CodeMirror.hint.anyword); CodeMirror.showHint(cm, CodeMirror.hint.anyword);
} }
editor.setOption("extraKeys", { editor.setOption("extraKeys", {
"Ctrl-Space": "autocomplete" "Ctrl-Space": "autocomplete"
@ -132,6 +132,8 @@ var executionMark;
highlightExecution = function(start, end) { highlightExecution = function(start, end) {
if (executionMark) if (executionMark)
executionMark.clear(); executionMark.clear();
if (start === 0 && end + 1 === editor.getValue().length)
return; // Do not hightlight the whole document.
executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" }); executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" });
} }
@ -145,3 +147,38 @@ isClean = function()
{ {
return editor.isClean(changeId); return editor.isClean(changeId);
} }
var annotation = null;
var compilationCompleteBool = true;
compilationError = function(line, column, content)
{
compilationCompleteBool = false;
window.setTimeout(function(){
if (compilationCompleteBool)
return;
line = parseInt(line);
column = parseInt(column);
if (line > 0)
line = line - 1;
if (column > 0)
column = column - 1;
if (annotation == null)
annotation = new ErrorAnnotation(editor, line, column, content);
else if (annotation.line !== line || annotation.column !== column || annotation.content !== content)
{
annotation.destroy();
annotation = new ErrorAnnotation(editor, line, column, content);
}
}, 500)
}
compilationComplete = function()
{
if (annotation !== null)
{
annotation.destroy();
annotation = null;
}
compilationCompleteBool = true;
}

5
mix/qml/js/ErrorLocationFormater.js

@ -16,12 +16,15 @@ function extractErrorInfo(raw, shortMessage)
{ {
_return.errorLocation = ErrorLocationFormater.formatLocation(reg[0], shortMessage); _return.errorLocation = ErrorLocationFormater.formatLocation(reg[0], shortMessage);
_return.errorDetail = detail.replace(reg[0], ""); _return.errorDetail = detail.replace(reg[0], "");
_return.line = reg[0].split(':')[1];
_return.column = reg[0].split(':')[2];
} }
else else
{ {
_return.errorLocation = ""; _return.errorLocation = "";
_return.errorDetail = detail; _return.errorDetail = detail;
_return.line = "";
_return.column = "";
} }
_return.errorLine = raw.split('\n')[1];
return _return; return _return;
} }

1
mix/web.qrc

@ -27,6 +27,7 @@
<file>qml/html/cm/closebrackets.js</file> <file>qml/html/cm/closebrackets.js</file>
<file>qml/html/cm/solidityToken.js</file> <file>qml/html/cm/solidityToken.js</file>
<file>qml/html/cm/javascript-hint.js</file> <file>qml/html/cm/javascript-hint.js</file>
<file>qml/html/cm/errorannotation.js</file>
<file>qml/html/cm/tern.js</file> <file>qml/html/cm/tern.js</file>
<file>qml/html/cm/ecma5spec.js</file> <file>qml/html/cm/ecma5spec.js</file>
<file>qml/html/cm/comment.js</file> <file>qml/html/cm/comment.js</file>

383
neth/main.cpp

@ -31,12 +31,15 @@
#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/VMFactory.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libwebthree/WebThree.h>
#if ETH_JSONRPC #if ETH_JSONRPC
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h> #include <jsonrpccpp/server/connectors/httpserver.h>
#endif #endif
#include <libwebthree/WebThree.h>
#include "BuildInfo.h" #include "BuildInfo.h"
#undef KEY_EVENT // from windows.h #undef KEY_EVENT // from windows.h
@ -68,26 +71,37 @@ void help()
<< "Usage neth [OPTIONS]" << endl << "Usage neth [OPTIONS]" << 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,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (Default: 15)." << 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
<< " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << 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
#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
<< " -K,--kill-blockchain First kill the blockchain." << endl
<< " -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
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -m,--mining <on/off> Enable mining (default: off)" << endl << " -m,--mining <on/off> Enable mining (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
<< " -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
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << 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 << " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl << " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl << " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl
<< " -V,--version Show the version and exit." << endl; << " -V,--version Show the version and exit." << endl
#if ETH_EVMJIT
<< " --jit Use EVM JIT (default: off)." << endl
#endif
;
exit(0); exit(0);
} }
@ -113,6 +127,10 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl << " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl << " contract Create a new contract with current secret." << endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl << " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " verbosity (<level>) Gets or sets verbosity level." << endl
<< " setblockfees <n> Set the block fee profit in the reference unit e.g. ¢ (Default: 15)" << endl
<< " setetherprice <p> Resets the ether price." << endl
<< " setpriority <p> Resets the transaction priority." << endl
<< " reset Resets ncurses windows" << endl << " reset Resets ncurses windows" << endl
<< " exit Exits the application." << endl; << " exit Exits the application." << endl;
} }
@ -319,7 +337,14 @@ int main(int argc, char** argv)
bool upnp = true; bool upnp = true;
bool useLocal = false; bool useLocal = false;
bool forceMining = false; bool forceMining = false;
bool killChain = false;
bool jit = false;
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string clientName; string clientName;
TransactionPriority priority = TransactionPriority::Medium;
double etherPrice = 30.679;
double blockFees = 15.0;
// Init defaults // Init defaults
Defaults::get(); Defaults::get();
@ -367,6 +392,10 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if (arg == "-K" || arg == "--kill-blockchain")
killChain = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i]; clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
@ -389,8 +418,58 @@ 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 == "-B" || arg == "--block-fees") && i + 1 < argc)
{
try
{
blockFees = stof(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
}
else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc)
{
try
{
etherPrice = stof(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
}
else if ((arg == "-P" || arg == "--priority") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
if (m == "lowest")
priority = TransactionPriority::Lowest;
else if (m == "low")
priority = TransactionPriority::Low;
else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
priority = TransactionPriority::Medium;
else if (m == "high")
priority = TransactionPriority::High;
else if (m == "highest")
priority = TransactionPriority::Highest;
else
try {
priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
}
catch (...) {
cerr << "Unknown " << arg << " option: " << m << endl;
return -1;
}
}
else if ((arg == "-m" || arg == "--mining") && i + 1 < argc) else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
{ {
string m = argv[++i]; string m = argv[++i];
@ -423,6 +502,28 @@ int main(int argc, char** argv)
peers = atoi(argv[++i]); peers = atoi(argv[++i]);
else if ((arg == "-t" || arg == "--miners") && i + 1 < argc) else if ((arg == "-t" || arg == "--miners") && i + 1 < argc)
miners = atoi(argv[++i]); miners = atoi(argv[++i]);
else if ((arg == "-o" || arg == "--mode") && i + 1 < argc)
{
string m = argv[++i];
if (m == "full")
mode = NodeMode::Full;
else if (m == "peer")
mode = NodeMode::PeerServer;
else
{
cerr << "Unknown mode: " << m << endl;
return -1;
}
}
else if (arg == "--jit")
{
#if ETH_EVMJIT
jit = true;
#else
cerr << "EVM JIT not enabled" << endl;
return -1;
#endif
}
else if (arg == "-h" || arg == "--help") else if (arg == "-h" || arg == "--help")
help(); help();
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")
@ -438,35 +539,41 @@ int main(int argc, char** argv)
clientName += "/"; clientName += "/";
cout << credits(); cout << credits();
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
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 = "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3( dev::WebThreeDirect web3(
"NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), clientImplString,
dbPath, dbPath,
false, killChain,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(), mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs, netPrefs,
&nodesState, &nodesState,
miners miners
); );
web3.setIdealPeerCount(peers); web3.setIdealPeerCount(peers);
std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
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->setGasPricer(gasPricer);
c->setForceMining(forceMining); c->setForceMining(forceMining);
c->setAddress(coinbase); c->setAddress(coinbase);
} }
cout << "Address: " << endl << toHex(us.address().asArray()) << endl; cout << "Transaction Signer: " << us.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl;
web3.startNetwork(); web3.startNetwork();
if (bootstrap) if (bootstrap)
web3.connect(Host::pocHost()); web3.connect(Host::pocHost());
if (remoteHost.size()) if (remoteHost.size())
web3.connect(remoteHost, remotePort); web3.connect(remoteHost, remotePort);
if (mining) if (c && mining)
c->startMining(); c->startMining();
#if ETH_JSONRPC #if ETH_JSONRPC
@ -474,11 +581,7 @@ int main(int argc, char** argv)
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector; unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1) if (jsonrpc > -1)
{ {
#if ETH_DEBUG jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", 1));
#else
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", 4));
#endif
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us}))); jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us}); jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
@ -612,6 +715,42 @@ int main(int argc, char** argv)
iss >> enable; iss >> enable;
c->setForceMining(isTrue(enable)); c->setForceMining(isTrue(enable));
} }
else if (c && cmd == "setblockfees")
{
iss >> blockFees;
gasPricer->setRefBlockFees(u256(blockFees * 1000));
cout << "Block fees: " << blockFees << endl;
}
else if (c && cmd == "setetherprice")
{
iss >> etherPrice;
gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice));
cout << "ether Price: " << etherPrice << endl;
}
else if (c && cmd == "setpriority")
{
string m;
iss >> m;
boost::to_lower(m);
if (m == "lowest")
priority = TransactionPriority::Lowest;
else if (m == "low")
priority = TransactionPriority::Low;
else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
priority = TransactionPriority::Medium;
else if (m == "high")
priority = TransactionPriority::High;
else if (m == "highest")
priority = TransactionPriority::Highest;
else
try {
priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
}
catch (...) {
cerr << "Unknown priority: " << m << endl;
}
cout << "Priority: " << (int)priority << "/8" << endl;
}
else if (cmd == "verbosity") else if (cmd == "verbosity")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
@ -655,7 +794,7 @@ int main(int argc, char** argv)
ccout << "Current secret:" << endl; ccout << "Current secret:" << endl;
ccout << toHex(us.secret().asArray()) << endl; ccout << toHex(us.secret().asArray()) << endl;
} }
else if (cmd == "block") else if (c && cmd == "block")
{ {
unsigned n = c->blockChain().details().number; unsigned n = c->blockChain().details().number;
ccout << "Current block # "; ccout << "Current block # ";
@ -668,13 +807,13 @@ int main(int argc, char** argv)
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms" << std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
<< endl; << endl;
} }
else if (cmd == "balance") else if (c && cmd == "balance")
{ {
u256 balance = c->balanceAt(us.address()); u256 balance = c->balanceAt(us.address());
ccout << "Current balance:" << endl; ccout << "Current balance:" << endl;
ccout << toString(balance) << endl; ccout << toString(balance) << endl;
} }
else if (cmd == "transact") else if (c && cmd == "transact")
{ {
auto const& bc = c->blockChain(); auto const& bc = c->blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
@ -716,6 +855,8 @@ int main(int argc, char** argv)
stringstream ssp; stringstream ssp;
ssp << fields[2]; ssp << fields[2];
ssp >> gasPrice; ssp >> gasPrice;
if (!gasPrice)
gasPrice = gasPricer->bid(priority);
string sechex = fields[4]; string sechex = fields[4];
string sdata = fields[5]; string sdata = fields[5];
cnote << "Data:"; cnote << "Data:";
@ -761,7 +902,7 @@ int main(int argc, char** argv)
} }
} }
} }
else if (cmd == "send") else if (c && cmd == "send")
{ {
vector<string> s; vector<string> s;
s.push_back("Address"); s.push_back("Address");
@ -812,7 +953,7 @@ int main(int argc, char** argv)
} }
} }
} }
else if (cmd == "contract") else if (c && cmd == "contract")
{ {
auto const& bc = c->blockChain(); auto const& bc = c->blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
@ -895,7 +1036,7 @@ int main(int argc, char** argv)
} }
} }
} }
else if (cmd == "inspect") else if (c && cmd == "inspect")
{ {
string rechex; string rechex;
iss >> rechex; iss >> rechex;
@ -941,111 +1082,119 @@ int main(int argc, char** argv)
interactiveHelp(); interactiveHelp();
else if (cmd == "exit") else if (cmd == "exit")
break; break;
else if (cmd != "")
cwarn << "Unrecognised command. Type 'help' for a list of available commands.";
// Clear cmd at each pass // Clear cmd at each pass
cmd = ""; cmd = "";
// Lock to prevent corrupt block-chain errors // Contracts and addresses count / offset
auto const& bc = c->blockChain(); int cc = 1;
ccout << "Genesis hash: " << bc.genesisHash() << endl; int ca = 0;
// Blocks if (c) {
y = 1; // Lock to prevent corrupt block-chain errors
for (auto h = bc.currentHash(); h != bc.genesisHash(); h = bc.details(h).parent) auto const& bc = c->blockChain();
{ ccout << "Genesis hash: " << bc.genesisHash() << endl;
auto d = bc.details(h);
string s = "# " + std::to_string(d.number) + ' ' + toString(h); // .abridged();
mvwaddnstr(blockswin, y++, x, s.c_str(), qwidth);
auto b = bc.block(h); // Blocks
for (auto const& i: RLP(b)[1]) y = 1;
for (auto h = bc.currentHash(); h != bc.genesisHash(); h = bc.details(h).parent)
{
auto d = bc.details(h);
string s = "# " + std::to_string(d.number) + ' ' + toString(h); // .abridged();
mvwaddnstr(blockswin, y++, x, s.c_str(), qwidth);
auto b = bc.block(h);
for (auto const& i: RLP(b)[1])
{
Transaction t(i.data(), CheckSignature::Sender);
auto s = t.receiveAddress() ?
boost::format(" %1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) %
(c->codeAt(t.receiveAddress(), PendingBlock).size() ? '*' : '-') %
toString(t.receiveAddress()) %
toString(formatBalance(t.value())) %
toString((unsigned)t.nonce()) :
boost::format(" %1% +> %2%: %3% [%4%]") %
toString(t.safeSender()) %
toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) %
toString(formatBalance(t.value())) %
toString((unsigned)t.nonce());
mvwaddnstr(blockswin, y++, x, s.str().c_str(), qwidth - 2);
if (y > qheight - 2)
break;
}
if (y > qheight - 2)
break;
}
// Pending
y = 1;
for (Transaction const& t: c->pending())
{ {
Transaction t(i.data(), CheckSignature::Sender);
auto s = t.receiveAddress() ? auto s = t.receiveAddress() ?
boost::format(" %1% %2%> %3%: %4% [%5%]") % boost::format("%1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) % toString(t.safeSender()) %
(c->codeAt(t.receiveAddress(), PendingBlock).size() ? '*' : '-') % (c->codeAt(t.receiveAddress(), PendingBlock).size() ? '*' : '-') %
toString(t.receiveAddress()) % toString(t.receiveAddress()) %
toString(formatBalance(t.value())) % toString(formatBalance(t.value())) %
toString((unsigned)t.nonce()) : toString((unsigned)t.nonce()) :
boost::format(" %1% +> %2%: %3% [%4%]") % boost::format("%1% +> %2%: %3% [%4%]") %
toString(t.safeSender()) % toString(t.safeSender()) %
toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) % toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) %
toString(formatBalance(t.value())) % toString(formatBalance(t.value())) %
toString((unsigned)t.nonce()); toString((unsigned)t.nonce());
mvwaddnstr(blockswin, y++, x, s.str().c_str(), qwidth - 2); mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth);
if (y > qheight - 2) if (y > height * 1 / 5 - 2)
break; break;
} }
if (y > qheight - 2)
break;
}
// Pending
y = 1;
for (Transaction const& t: c->pending())
{
auto s = t.receiveAddress() ?
boost::format("%1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) %
(c->codeAt(t.receiveAddress(), PendingBlock).size() ? '*' : '-') %
toString(t.receiveAddress()) %
toString(formatBalance(t.value())) %
toString((unsigned)t.nonce()) :
boost::format("%1% +> %2%: %3% [%4%]") %
toString(t.safeSender()) %
toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) %
toString(formatBalance(t.value())) %
toString((unsigned)t.nonce());
mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth);
if (y > height * 1 / 5 - 2)
break;
}
// Contracts and addresses
y = 1;
auto acs = c->addresses();
ca = acs.size();
for (auto const& i: acs)
if (c->codeAt(i, PendingBlock).size())
{
auto s = boost::format("%1%%2% : %3% [%4%]") %
toString(i) %
pretty(i, c->postState()) %
toString(formatBalance(c->balanceAt(i))) %
toString((unsigned)c->countAt(i, PendingBlock));
mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth);
if (cc > qheight - 2)
break;
}
for (auto const& i: acs)
if (c->codeAt(i, PendingBlock).empty())
{
auto s = boost::format("%1%%2% : %3% [%4%]") %
toString(i) %
pretty(i, c->postState()) %
toString(formatBalance(c->balanceAt(i))) %
toString((unsigned)c->countAt(i, PendingBlock));
mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4);
if (y > height * 3 / 5 - 4)
break;
}
// Contracts and addresses // Peers
y = 1; y = 1;
int cc = 1; for (PeerSessionInfo const& i: web3.peers())
auto acs = c->addresses();
for (auto const& i: acs)
if (c->codeAt(i, PendingBlock).size())
{
auto s = boost::format("%1%%2% : %3% [%4%]") %
toString(i) %
pretty(i, c->postState()) %
toString(formatBalance(c->balanceAt(i))) %
toString((unsigned)c->countAt(i, PendingBlock));
mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth);
if (cc > qheight - 2)
break;
}
for (auto const& i: acs)
if (c->codeAt(i, PendingBlock).empty())
{ {
auto s = boost::format("%1%%2% : %3% [%4%]") % auto s = boost::format("%1% ms - %2%:%3% - %4%") %
toString(i) % toString(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()) %
pretty(i, c->postState()) % i.host %
toString(formatBalance(c->balanceAt(i))) % toString(i.port) %
toString((unsigned)c->countAt(i, PendingBlock)); i.clientVersion;
mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4); mvwaddnstr(peerswin, y++, x, s.str().c_str(), qwidth);
if (y > height * 3 / 5 - 4) if (y > height * 2 / 5 - 4)
break; break;
} }
// Peers
y = 1;
for (PeerSessionInfo const& i: web3.peers())
{
auto s = boost::format("%1% ms - %2%:%3% - %4%") %
toString(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()) %
i.host %
toString(i.port) %
i.clientVersion;
mvwaddnstr(peerswin, y++, x, s.str().c_str(), qwidth);
if (y > height * 2 / 5 - 4)
break;
} }
box(consolewin, 0, 0); box(consolewin, 0, 0);
@ -1058,31 +1207,41 @@ int main(int argc, char** argv)
// Balance // Balance
stringstream ssb; stringstream ssb;
u256 balance = c->balanceAt(us.address()); u256 balance;
ssb << "Balance: " << formatBalance(balance); if (c)
balance = c->balanceAt(us.address());
ssb << "Balance: ";
if (c)
ssb << formatBalance(balance);
mvwprintw(consolewin, 0, x, ssb.str().c_str()); mvwprintw(consolewin, 0, x, ssb.str().c_str());
// Block // Block
mvwprintw(blockswin, 0, x, "Block # "); mvwprintw(blockswin, 0, x, "Block # ");
unsigned n = c->blockChain().details().number; if (c) {
mvwprintw(blockswin, 0, 10, toString(n).c_str()); unsigned n = c->blockChain().details().number;
mvwprintw(blockswin, 0, 10, toString(n).c_str());
}
// Pending // Pending
string pc; stringstream pc;
pc = "Pending: " + toString(c->pending().size()); pc << "Pending: ";
mvwprintw(pendingwin, 0, x, pc.c_str()); if (c)
pc << toString(c->pending().size());
else
pc << 0;
mvwprintw(pendingwin, 0, x, pc.str().c_str());
// Contracts // Contracts
string sc = "Contracts: "; stringstream sc;
sc += toString(cc - 1); sc << "Contracts: " << cc - 1;
mvwprintw(contractswin, 0, x, sc.c_str()); mvwprintw(contractswin, 0, x, sc.str().c_str());
// Peers // Peers
mvwprintw(peerswin, 0, x, "Peers: "); mvwprintw(peerswin, 0, x, "Peers: ");
mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str()); mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str());
// Mining flag // Mining flag
if (c->isMining()) if (c && c->isMining())
{ {
mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON"); mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON");
dev::eth::MineProgress p = c->miningProgress(); dev::eth::MineProgress p = c->miningProgress();
@ -1095,9 +1254,9 @@ int main(int argc, char** argv)
wmove(consolewin, 1, x); wmove(consolewin, 1, x);
// Addresses // Addresses
string ac; stringstream ac;
ac = "Addresses: " + toString(acs.size()); ac << "Addresses: " << ca;
mvwprintw(addswin, 0, x, ac.c_str()); mvwprintw(addswin, 0, x, ac.str().c_str());
wrefresh(consolewin); wrefresh(consolewin);

Loading…
Cancel
Save