Browse Source

Merge remote-tracking branch 'up/develop' into bugFix

Conflicts:
	mix/MixClient.cpp
	mix/MixClient.h
cl-refactor
yann300 10 years ago
parent
commit
7dcf564842
  1. 5
      CMakeLists.txt
  2. 16
      abi/CMakeLists.txt
  3. 343
      abi/main.cpp
  4. 4
      alethzero/Main.ui
  5. 27
      alethzero/MainWin.cpp
  6. 4
      alethzero/Transact.cpp
  7. 6
      cmake/EthCompilerSettings.cmake
  8. 22
      cmake/EthDependencies.cmake
  9. 40
      cmake/EthUtils.cmake
  10. 15
      cmake/scripts/runtest.cmake
  11. 10
      eth/main.cpp
  12. 35
      ethrpctest/CMakeLists.txt
  13. 129
      ethrpctest/CommandLineInterface.cpp
  14. 46
      ethrpctest/CommandLineInterface.h
  15. 34
      ethrpctest/main.cpp
  16. 4
      evmjit/libevmjit-cpp/Env.cpp
  17. 17
      evmjit/libevmjit/ExecutionEngine.cpp
  18. 6
      libethereum/BlockChain.h
  19. 380
      libethereum/Client.cpp
  20. 135
      libethereum/Client.h
  21. 402
      libethereum/ClientBase.cpp
  22. 167
      libethereum/ClientBase.h
  23. 5
      libethereum/Executive.cpp
  24. 2
      libethereum/Executive.h
  25. 6
      libethereum/Interface.h
  26. 4
      libethereum/State.cpp
  27. 4
      libethereum/State.h
  28. 4
      libethereum/Transaction.cpp
  29. 3
      libethereum/Transaction.h
  30. 2
      libp2p/RLPxHandshake.h
  31. 9
      libp2p/UDP.h
  32. 1
      libsolidity/ExpressionCompiler.h
  33. 13
      libsolidity/Token.h
  34. 100
      libtestutils/BlockChainLoader.cpp
  35. 52
      libtestutils/BlockChainLoader.h
  36. 34
      libtestutils/CMakeLists.txt
  37. 80
      libtestutils/Common.cpp
  38. 44
      libtestutils/Common.h
  39. 32
      libtestutils/FixedClient.cpp
  40. 59
      libtestutils/FixedClient.h
  41. 22
      libtestutils/FixedWebThreeServer.cpp
  42. 57
      libtestutils/FixedWebThreeServer.h
  43. 56
      libtestutils/StateLoader.cpp
  44. 45
      libtestutils/StateLoader.h
  45. 42
      libtestutils/TransientDirectory.cpp
  46. 50
      libtestutils/TransientDirectory.h
  47. 31
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  48. 3
      libweb3jsonrpc/WebThreeStubServerBase.h
  49. 4
      mix/ClientModel.cpp
  50. 318
      mix/MixClient.cpp
  51. 69
      mix/MixClient.h
  52. 6
      mix/qml/Debugger.qml
  53. 16
      mix/qml/WebCodeEditor.qml
  54. 46
      mix/qml/html/cm/errorannotation.js
  55. 13
      mix/qml/html/cm/solarized.css
  56. 1
      mix/qml/html/codeeditor.html
  57. 73
      mix/qml/html/codeeditor.js
  58. 5
      mix/qml/js/ErrorLocationFormater.js
  59. 1
      mix/web.qrc
  60. 385
      neth/main.cpp
  61. 7
      test/transaction.cpp
  62. 15
      test/ttTransactionTestFiller.json

5
CMakeLists.txt

@ -160,7 +160,6 @@ if (EVMJIT)
endif()
add_subdirectory(libdevcore)
add_subdirectory(rlp)
add_subdirectory(libevmcore)
add_subdirectory(liblll)
@ -178,6 +177,7 @@ endif()
if (JSONRPC)
add_subdirectory(libweb3jsonrpc)
add_subdirectory(ethrpctest)
endif()
add_subdirectory(secp256k1)
@ -195,10 +195,13 @@ add_subdirectory(libevm)
add_subdirectory(libethereum)
add_subdirectory(libwebthree)
add_subdirectory(libtestutils)
add_subdirectory(test)
if (NOT JUSTTESTS)
add_subdirectory(rlp)
add_subdirectory(abi)
add_subdirectory(eth)
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")

16
abi/CMakeLists.txt

@ -0,0 +1,16 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
set(EXECUTABLE abi)
add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} ethereum)
install( TARGETS ${EXECUTABLE} DESTINATION bin)

343
abi/main.cpp

@ -0,0 +1,343 @@
/*
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 main.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* RLP tool.
*/
#include <fstream>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include "../test/JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h>
#include <libethereum/Client.h>
using namespace std;
using namespace dev;
namespace js = json_spirit;
void help()
{
cout
<< "Usage abi enc <method_name> (<arg1>, (<arg2>, ... ))" << endl
<< " abi enc -a <abi.json> <method_name> (<arg1>, (<arg2>, ... ))" << endl
<< " abi dec -a <abi.json> [ <signature> | <unique_method_name> ]" << endl
<< "Options:" << endl
<< " -a,--abi-file <filename> Specify the JSON ABI file." << endl
<< " -h,--help Print this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl
<< "Input options:" << endl
<< " -p,--prefix Require all input formats to be prefixed e.g. 0x for hex, . for decimal, @ for binary." << endl
<< " -P,--no-prefix Require no input format to be prefixed." << endl
<< " -t,--typing Require all arguments to be typed e.g. b32: (bytes32), u64: (uint64), b[]: (byte[]), i: (int256)." << endl
<< " -T,--no-typing Require no arguments to be typed." << endl
<< "Output options:" << endl
<< " -i,--index <n> Output only the nth (counting from 0) return value." << endl
<< " -d,--decimal All data should be displayed as decimal." << endl
<< " -x,--hex Display all data as hex." << endl
<< " -b,--binary Display all data as binary." << endl
<< " -p,--prefix Prefix by a base identifier." << endl
<< " -z,--no-zeroes Remove any leading zeroes from the data." << endl
<< " -n,--no-nulls Remove any trailing nulls from the data." << endl
;
exit(0);
}
void version()
{
cout << "abi version " << dev::Version << endl;
exit(0);
}
enum class Mode
{
Encode,
Decode
};
enum class Encoding
{
Auto,
Decimal,
Hex,
Binary,
};
enum class Tristate
{
False = false,
True = true,
Mu
};
enum class Format
{
Binary,
Hex,
Decimal
};
struct InvalidUserString: public Exception {};
struct InvalidFormat: public Exception {};
enum class Base
{
Unknown,
Bytes,
Address,
Int,
Uint,
Fixed
};
struct ABIType
{
Base base = Base::Unknown;
unsigned size = 32;
unsigned ssize = 0;
vector<int> dims;
ABIType() = default;
ABIType(std::string const& _s)
{
if (_s.size() < 1)
return;
switch (_s[0])
{
case 'b': base = Base::Bytes; break;
case 'a': base = Base::Address; break;
case 'i': base = Base::Int; break;
case 'u': base = Base::Uint; break;
case 'f': base = Base::Fixed; break;
default: throw InvalidFormat();
}
if (_s.size() < 2)
{
if (base == Base::Fixed)
size = ssize = 16;
else
size = 32;
return;
}
if (_s.find_first_of('x') == string::npos)
size = stoi(_s.substr(1));
else
{
size = stoi(_s.substr(1, _s.find_first_of('x') - 1));
ssize = stoi(_s.substr(_s.find_first_of('x') + 1));
}
}
string canon() const
{
string ret;
switch (base)
{
case Base::Bytes: ret = "bytes" + toString(size); break;
case Base::Address: ret = "address"; break;
case Base::Int: ret = "int" + toString(size); break;
case Base::Uint: ret = "uint" + toString(size); break;
case Base::Fixed: ret = "fixed" + toString(size) + "x" + toString(ssize); break;
default: throw InvalidFormat();
}
for (int i: dims)
ret += "[" + ((i > -1) ? toString(i) : "") + "]";
return ret;
}
void noteHexInput(unsigned _nibbles) { if (base == Base::Unknown) { if (_nibbles == 40) base = Base::Address; else { base = Base::Bytes; size = _nibbles / 2; } } }
void noteBinaryInput() { if (base == Base::Unknown) { base = Base::Bytes; size = 32; } }
void noteDecimalInput() { if (base == Base::Unknown) { base = Base::Uint; size = 32; } }
};
tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix, Tristate _typing)
{
ABIType type;
string val;
if (_typing == Tristate::True || (_typing == Tristate::Mu && _arg.find(':') != string::npos))
{
if (_arg.find(':') == string::npos)
throw InvalidUserString();
type = ABIType(_arg.substr(0, _arg.find(':')));
val = _arg.substr(_arg.find(':') + 1);
}
else
val = _arg;
if (_prefix != Tristate::False)
{
if (val.substr(0, 2) == "0x")
{
type.noteHexInput(val.size() - 2);
return make_tuple(fromHex(val), type, Format::Hex);
}
if (val.substr(0, 1) == ".")
{
type.noteDecimalInput();
return make_tuple(toCompactBigEndian(bigint(val.substr(1))), type, Format::Decimal);
}
if (val.substr(0, 1) == "@")
{
type.noteBinaryInput();
return make_tuple(asBytes(val.substr(1)), type, Format::Binary);
}
}
if (_prefix != Tristate::True)
{
if (_arg.find_first_not_of("0123456789") == string::npos)
{
type.noteDecimalInput();
return make_tuple(toCompactBigEndian(bigint(val)), type, Format::Decimal);
}
if (_arg.find_first_not_of("0123456789abcdefABCDEF") == string::npos)
{
type.noteHexInput(val.size());
return make_tuple(fromHex(val), type, Format::Hex);
}
type.noteBinaryInput();
return make_tuple(asBytes(_arg), type, Format::Binary);
}
throw InvalidUserString();
}
void userOutput(ostream& _out, bytes const& _data, Encoding _e)
{
switch (_e)
{
case Encoding::Binary:
_out.write((char const*)_data.data(), _data.size());
break;
default:
_out << toHex(_data) << endl;
}
}
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;
}
int main(int argc, char** argv)
{
Encoding encoding = Encoding::Auto;
Mode mode = Mode::Encode;
string abiFile;
string method;
Tristate prefix = Tristate::Mu;
Tristate typePrefix = Tristate::Mu;
bool clearZeroes = false;
bool clearNulls = false;
bool verbose = false;
int outputIndex = -1;
vector<tuple<bytes, ABIType, Format>> args;
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if (arg == "-h" || arg == "--help")
help();
else if (arg == "enc" && i == 1)
mode = Mode::Encode;
else if (arg == "dec" && i == 1)
mode = Mode::Decode;
else if ((arg == "-a" || arg == "--abi") && argc > i)
abiFile = argv[++i];
else if ((arg == "-i" || arg == "--index") && argc > i)
outputIndex = atoi(argv[++i]);
else if (arg == "-p" || arg == "--prefix")
prefix = Tristate::True;
else if (arg == "-P" || arg == "--no-prefix")
prefix = Tristate::False;
else if (arg == "-t" || arg == "--typing")
typePrefix = Tristate::True;
else if (arg == "-T" || arg == "--no-typing")
typePrefix = Tristate::False;
else if (arg == "-z" || arg == "--no-zeroes")
clearZeroes = true;
else if (arg == "-n" || arg == "--no-nulls")
clearNulls = true;
else if (arg == "-v" || arg == "--verbose")
verbose = true;
else if (arg == "-x" || arg == "--hex")
encoding = Encoding::Hex;
else if (arg == "-d" || arg == "--decimal" || arg == "--dec")
encoding = Encoding::Decimal;
else if (arg == "-b" || arg == "--binary" || arg == "--bin")
encoding = Encoding::Binary;
else if (arg == "-v" || arg == "--verbose")
version();
else if (arg == "-V" || arg == "--version")
version();
else if (method.empty())
method = arg;
else
args.push_back(fromUser(arg, prefix, typePrefix));
}
string abi;
if (abiFile == "--")
for (int i = cin.get(); i != -1; i = cin.get())
abi.push_back((char)i);
else if (!abiFile.empty())
abi = contentsString(abiFile);
if (mode == Mode::Encode)
{
bytes ret;
if (abi.empty())
{
if (!method.empty())
{
string methodArgs;
for (auto const& arg: args)
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);
}
else if (mode == Mode::Decode)
{
// TODO: read abi to determine output format.
(void)encoding;
(void)clearZeroes;
(void)clearNulls;
(void)outputIndex;
}
return 0;
}

4
alethzero/Main.ui

@ -208,7 +208,7 @@
<addaction name="menu_Debug"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="dockWidget_2">
<widget class="QDockWidget" name="dockWidget_accounts">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
@ -566,7 +566,7 @@
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_6">
<widget class="QDockWidget" name="dockWidget_contracts">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>

27
alethzero/MainWin.cpp

@ -135,6 +135,11 @@ Main::Main(QWidget *parent) :
// ui->log->addItem(QString::fromStdString(s));
};
#if !ETH_FATDB
delete ui->dockWidget_accounts;
delete ui->dockWidget_contracts;
#endif
#if ETH_DEBUG
m_servers.append("localhost:30300");
#endif
@ -164,7 +169,7 @@ Main::Main(QWidget *parent) :
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), false, {"eth", "shh"}, p2p::NetworkPreferences(), network));
m_httpConnector.reset(new jsonrpc::HttpServer(8080));
m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads));
m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), keysAsVector(m_myKeys), this));
connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString)));
m_server->setIdentities(keysAsVector(owned()));
@ -1036,6 +1041,7 @@ void Main::refreshPending()
void Main::refreshAccounts()
{
#if ETH_FATDB
cwatch << "refreshAccounts()";
ui->accounts->clear();
ui->contracts->clear();
@ -1053,6 +1059,7 @@ void Main::refreshAccounts()
->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size));
}
}
#endif
}
void Main::refreshBlockCount()
@ -1626,16 +1633,22 @@ void Main::on_ourAccounts_doubleClicked()
void Main::on_accounts_doubleClicked()
{
auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
if (ui->accounts->count())
{
auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
}
void Main::on_contracts_doubleClicked()
{
auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
if (ui->contracts->count())
{
auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
}
static shh::FullTopic topicFromText(QString _s)

4
alethzero/Transact.cpp

@ -328,8 +328,8 @@ void Transact::rejigData()
to = m_context->fromString(ui->destination->currentText());
er = ethereum()->call(s, value(), to, m_data, ethereum()->gasLimitRemaining(), gasPrice());
}
gasNeeded = (qint64)er.gasUsed;
htmlInfo = QString("<div class=\"info\"><span class=\"icon\">INFO</span> Gas required: %1 total = %2 base, %3 exec</div>").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas) + htmlInfo;
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded);
htmlInfo = QString("<div class=\"info\"><span class=\"icon\">INFO</span> Gas required: %1 total = %2 base, %3 exec [%4 refunded later]</div>").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo;
if (er.excepted != TransactionException::None)
{

6
cmake/EthCompilerSettings.cmake

@ -38,12 +38,14 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# disable decorated name length exceeded, name was truncated (4503)
# disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests)
# declare Windows XP requirement
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501)
# undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX)
# disable empty object file warning
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# warning LNK4099: pdb was not found with lib
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075")
# stack size 16MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
# windows likes static
set(ETH_STATIC 1)

22
cmake/EthDependencies.cmake

@ -30,6 +30,9 @@ if (APPLE)
set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/qt5")
endif()
find_program(CTEST_COMMAND ctest)
message(STATUS "ctest path: ${CTEST_COMMAND}")
# Dependencies must have a version number, to ensure reproducible build. The version provided here is the one that is in the extdep repository. If you use system libraries, version numbers may be different.
find_package (CryptoPP 5.6.2 EXACT REQUIRED)
@ -114,14 +117,17 @@ if (NOT HEADLESS)
# find all of the Qt packages
# remember to use 'Qt' instead of 'QT', cause unix is case sensitive
# TODO make headless client optional
find_package (Qt5Core REQUIRED)
find_package (Qt5Gui REQUIRED)
find_package (Qt5Quick REQUIRED)
find_package (Qt5Qml REQUIRED)
find_package (Qt5Network REQUIRED)
find_package (Qt5Widgets REQUIRED)
find_package (Qt5WebEngine REQUIRED)
find_package (Qt5WebEngineWidgets REQUIRED)
set (ETH_QT_VERSION 5.4)
find_package (Qt5Core ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Gui ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Quick ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Qml ${ETH_QT_VERSION} 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
if (APPLE)

40
cmake/EthUtils.cmake

@ -22,3 +22,43 @@ macro(replace_if_different SOURCE DST)
endif()
endmacro()
macro(eth_add_test NAME)
# parse arguments here
set(commands)
set(current_command "")
foreach (arg ${ARGN})
if (arg STREQUAL "ARGS")
if (current_command)
list(APPEND commands ${current_command})
endif()
set(current_command "")
else ()
set(current_command "${current_command} ${arg}")
endif()
endforeach(arg)
list(APPEND commands ${current_command})
message(STATUS "test: ${NAME} | ${commands}")
# create tests
set(index 0)
list(LENGTH commands count)
while (index LESS count)
list(GET commands ${index} test_arguments)
set(run_test "--run_test=${NAME}")
add_test(NAME "${NAME}.${index}" COMMAND testeth ${run_test} ${test_arguments})
math(EXPR index "${index} + 1")
endwhile(index LESS count)
# add target to run them
add_custom_target("test.${NAME}"
DEPENDS testeth
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -DETH_TEST_NAME="${NAME}" -DCTEST_COMMAND="${CTEST_COMMAND}" -P "${ETH_SCRIPTS_DIR}/runtest.cmake"
)
endmacro()

15
cmake/scripts/runtest.cmake

@ -0,0 +1,15 @@
# Should be used to run ctest
#
# example usage:
# cmake -DETH_TEST_NAME=TestInterfaceStub -DCTEST_COMMAND=/path/to/ctest -P scripts/runtest.cmake
if (NOT CTEST_COMMAND)
message(FATAL_ERROR "ctest could not be found!")
endif()
# verbosity is off, cause BOOST_MESSAGE is not thread safe and output is a trash
# see https://codecrafter.wordpress.com/2012/11/01/c-unit-test-framework-adapter-part-3/
#
# output might not be usefull cause of thread safety issue
execute_process(COMMAND ${CTEST_COMMAND} --force-new-ctest-process -C Debug --output-on-failure -j 4 -R "${ETH_TEST_NAME}[.].*")

10
eth/main.cpp

@ -117,7 +117,7 @@ void help()
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
#if ETH_JSONRPC
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl
#endif
<< " -K,--kill-blockchain First kill the blockchain." << endl
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
@ -370,7 +370,7 @@ int main(int argc, char** argv)
interactive = true;
#if ETH_JSONRPC
else if ((arg == "-j" || arg == "--json-rpc"))
jsonrpc = jsonrpc == -1 ? 8080 : jsonrpc;
jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc)
jsonrpc = atoi(argv[++i]);
#endif
@ -457,7 +457,7 @@ int main(int argc, char** argv)
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1)
{
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc));
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
@ -582,8 +582,8 @@ int main(int argc, char** argv)
else if (cmd == "jsonstart")
{
if (jsonrpc < 0)
jsonrpc = 8080;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc));
jsonrpc = SensibleHttpPort;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();

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);
if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024)
{
_env->subBalance(endowment);
u256 gas = *io_gas;
h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight);
*io_gas = static_cast<int64_t>(gas);
@ -89,10 +88,7 @@ extern "C"
auto ret = false;
auto callGas = u256{_callGas};
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
{
_env->subBalance(value);
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
return ret;

17
evmjit/libevmjit/ExecutionEngine.cpp

@ -4,6 +4,8 @@
#include <mutex>
#include <iostream>
#include <unordered_map>
#include <cstdlib>
#include <cstring>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
@ -82,7 +84,20 @@ void parseOptions()
{
static llvm::llvm_shutdown_obj shutdownObj{};
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");
}
}

6
libethereum/BlockChain.h

@ -65,6 +65,7 @@ ldb::Slice toSlice(h256 _h, unsigned _sub = 0);
using BlocksHash = std::map<h256, bytes>;
using TransactionHashes = h256s;
using UncleHashes = h256s;
enum {
ExtraDetails = 0,
@ -130,7 +131,10 @@ public:
TransactionHashes transactionHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }
TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); }
/// Get a list of transaction hashes for a given block. Thread-safe.
/// Get a list of uncle hashes for a given block. Thread-safe.
UncleHashes uncleHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[2]) ret.push_back(sha3(t.data())); return ret; }
UncleHashes uncleHashes() const { return uncleHashes(currentHash()); }
h256 numberHash(u256 _index) const { if (!_index) return genesisHash(); return queryExtras<BlockHash, ExtraBlockHash>(h256(_index), m_blockHashes, x_blockHashes, NullBlockHash).value; }
/** Get the block blooms for a number of blocks. Thread-safe.

380
libethereum/Client.cpp

@ -186,11 +186,6 @@ void Client::doneWorking()
m_postMine = m_preMine;
}
void Client::flushTransactions()
{
doWork();
}
void Client::killChain()
{
bool wasMining = isMining();
@ -249,64 +244,9 @@ void Client::clearPending()
noteChanged(changeds);
}
unsigned Client::installWatch(h256 _h, Reaping _r)
{
unsigned ret;
{
Guard l(m_filterLock);
ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0;
m_watches[ret] = ClientWatch(_h, _r);
cwatch << "+++" << ret << _h.abridged();
}
auto ch = logs(ret);
if (ch.empty())
ch.push_back(InitialChange);
{
Guard l(m_filterLock);
swap(m_watches[ret].changes, ch);
}
return ret;
}
unsigned Client::installWatch(LogFilter const& _f, Reaping _r)
{
h256 h = _f.sha3();
{
Guard l(m_filterLock);
if (!m_filters.count(h))
{
cwatch << "FFF" << _f << h.abridged();
m_filters.insert(make_pair(h, _f));
}
}
return installWatch(h, _r);
}
bool Client::uninstallWatch(unsigned _i)
{
cwatch << "XXX" << _i;
Guard l(m_filterLock);
auto it = m_watches.find(_i);
if (it == m_watches.end())
return false;
auto id = it->second.id;
m_watches.erase(it);
auto fit = m_filters.find(id);
if (fit != m_filters.end())
if (!--fit->second.refCount)
{
cwatch << "*X*" << fit->first << ":" << fit->second.filter;
m_filters.erase(fit);
}
return true;
}
void Client::noteChanged(h256Set const& _filters)
{
Guard l(m_filterLock);
Guard l(x_filtersWatches);
if (_filters.size())
cnote << "noteChanged(" << _filters << ")";
// accrue all changes left in each filter into the watches.
@ -324,42 +264,9 @@ void Client::noteChanged(h256Set const& _filters)
i.second.changes.clear();
}
LocalisedLogEntries Client::peekWatch(unsigned _watchId) const
{
Guard l(m_filterLock);
#if ETH_DEBUG
cdebug << "peekWatch" << _watchId;
#endif
auto& w = m_watches.at(_watchId);
#if ETH_DEBUG
cdebug << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
#endif
w.lastPoll = chrono::system_clock::now();
return w.changes;
}
LocalisedLogEntries Client::checkWatch(unsigned _watchId)
{
Guard l(m_filterLock);
LocalisedLogEntries ret;
#if ETH_DEBUG && 0
cdebug << "checkWatch" << _watchId;
#endif
auto& w = m_watches.at(_watchId);
#if ETH_DEBUG && 0
cdebug << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
#endif
std::swap(ret, w.changes);
w.lastPoll = chrono::system_clock::now();
return ret;
}
void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash)
{
Guard l(m_filterLock);
Guard l(x_filtersWatches);
for (pair<h256 const, InstalledFilter>& i: m_filters)
if (i.second.filter.envelops(RelativeBlock::Pending, m_bc.number() + 1))
{
@ -381,7 +288,7 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed)
auto d = m_bc.info(_block);
auto br = m_bc.receipts(_block);
Guard l(m_filterLock);
Guard l(x_filtersWatches);
for (pair<h256 const, InstalledFilter>& i: m_filters)
if (i.second.filter.envelops(RelativeBlock::Latest, d.number) && i.second.filter.matches(d.logBloom))
// acceptable number & looks like block may contain a matching log entry.
@ -475,68 +382,6 @@ void Client::setupState(State& _s)
_s.commitToMine(m_bc);
}
void Client::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
startWorking();
u256 n;
{
ReadGuard l(x_stateDB);
n = m_postMine.transactionsFrom(toAddress(_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));
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged());
cnote << "New transaction " << t;
m_tq.attemptImport(t.rlp());
}
ExecutionResult Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber)
{
ExecutionResult ret;
try
{
u256 n;
State temp;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
{
ReadGuard l(x_stateDB);
temp = asOf(_blockNumber);
n = temp.transactionsFrom(toAddress(_secret));
}
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
ret = temp.execute(m_bc, t.rlp(), Permanence::Reverted);
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
return ret;
}
ExecutionResult Client::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber)
{
ExecutionResult ret;
try
{
u256 n;
State temp;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
{
ReadGuard l(x_stateDB);
temp = asOf(_blockNumber);
n = temp.transactionsFrom(toAddress(_secret));
}
Transaction t(_value, _gasPrice, _gas, _data, n, _secret);
ret = temp.execute(m_bc, t.rlp(), Permanence::Reverted);
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
return ret;
}
ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice)
{
ExecutionResult ret;
@ -561,28 +406,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
return ret;
}
Address Client::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
startWorking();
u256 n;
{
ReadGuard l(x_stateDB);
n = m_postMine.transactionsFrom(toAddress(_secret));
}
Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
cnote << "New transaction " << t;
m_tq.attemptImport(t.rlp());
return right160(sha3(rlpList(t.sender(), t.nonce())));
}
void Client::inject(bytesConstRef _rlp)
{
startWorking();
m_tq.attemptImport(_rlp);
}
pair<h256, u256> Client::getWork()
{
Guard l(x_remoteMiner);
@ -712,7 +535,7 @@ void Client::doWork()
// watches garbage collection
vector<unsigned> toUninstall;
{
Guard l(m_filterLock);
Guard l(x_filtersWatches);
for (auto key: keysOf(m_watches))
if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20))
{
@ -730,15 +553,15 @@ void Client::doWork()
}
}
State Client::asOf(unsigned _h) const
State Client::asOf(h256 const& _block) const
{
ReadGuard l(x_stateDB);
if (_h == PendingBlock)
return m_postMine;
else if (_h == LatestBlock)
return m_preMine;
else
return State(m_stateDB, m_bc, m_bc.numberHash(_h));
return State(m_stateDB, bc(), _block);
}
void Client::prepareForTransaction()
{
startWorking();
}
State Client::state(unsigned _txi, h256 _block) const
@ -759,183 +582,14 @@ eth::State Client::state(unsigned _txi) const
return m_postMine.fromPending(_txi);
}
StateDiff Client::diff(unsigned _txi, BlockNumber _block) const
{
State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
StateDiff Client::diff(unsigned _txi, h256 _block) const
{
State st = state(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
std::vector<Address> Client::addresses(BlockNumber _block) const
{
vector<Address> ret;
for (auto const& i: asOf(_block).addresses())
ret.push_back(i.first);
return ret;
}
u256 Client::balanceAt(Address _a, BlockNumber _block) const
{
return asOf(_block).balance(_a);
}
std::map<u256, u256> Client::storageAt(Address _a, BlockNumber _block) const
{
return asOf(_block).storage(_a);
}
u256 Client::countAt(Address _a, BlockNumber _block) const
{
return asOf(_block).transactionsFrom(_a);
}
u256 Client::stateAt(Address _a, u256 _l, BlockNumber _block) const
{
return asOf(_block).storage(_a, _l);
}
bytes Client::codeAt(Address _a, BlockNumber _block) const
{
return asOf(_block).code(_a);
}
Transaction Client::transaction(h256 _transactionHash) const
{
return Transaction(m_bc.transaction(_transactionHash), CheckSignature::Range);
}
Transaction Client::transaction(h256 _blockHash, unsigned _i) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
if (_i < b[1].itemCount())
return Transaction(b[1][_i].data(), CheckSignature::Range);
else
return Transaction();
}
BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data());
else
return BlockInfo();
}
unsigned Client::transactionCount(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return b[1].itemCount();
}
unsigned Client::uncleCount(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return b[2].itemCount();
}
Transactions Client::transactions(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
Transactions res;
for (unsigned i = 0; i < b[1].itemCount(); i++)
res.emplace_back(b[1][i].data(), CheckSignature::Range);
return res;
}
TransactionHashes Client::transactionHashes(h256 _blockHash) const
{
return m_bc.transactionHashes(_blockHash);
}
LocalisedLogEntries Client::logs(unsigned _watchId) const
void Client::inject(bytesConstRef _rlp)
{
LogFilter f;
try
{
Guard l(m_filterLock);
f = m_filters.at(m_watches.at(_watchId).id).filter;
}
catch (...)
{
return LocalisedLogEntries();
}
return logs(f);
startWorking();
m_tq.attemptImport(_rlp);
}
LocalisedLogEntries Client::logs(LogFilter const& _f) const
void Client::flushTransactions()
{
LocalisedLogEntries ret;
unsigned begin = min<unsigned>(m_bc.number() + 1, (unsigned)_f.latest());
unsigned end = min(m_bc.number(), min(begin, (unsigned)_f.earliest()));
// Handle pending transactions differently as they're not on the block chain.
if (begin > m_bc.number())
{
ReadGuard l(x_stateDB);
for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
{
// Might have a transaction that contains a matching log.
TransactionReceipt const& tr = m_postMine.receipt(i);
auto sha3 = m_postMine.pending()[i].sha3();
LogEntries le = _f.matches(tr);
if (le.size())
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, sha3));
}
begin = m_bc.number();
}
set<unsigned> matchingBlocks;
for (auto const& i: _f.bloomPossibilities())
for (auto u: m_bc.withBlockBloom(i, end, begin))
matchingBlocks.insert(u);
#if ETH_DEBUG
unsigned falsePos = 0;
#endif
for (auto n: matchingBlocks)
{
#if ETH_DEBUG
int total = 0;
#endif
auto h = m_bc.numberHash(n);
auto receipts = m_bc.receipts(h).receipts;
for (size_t i = 0; i < receipts.size(); i++)
{
TransactionReceipt receipt = receipts[i];
if (_f.matches(receipt.bloom()))
{
auto info = m_bc.info(h);
auto h = transaction(info.hash, i).sha3();
LogEntries le = _f.matches(receipt);
if (le.size())
{
#if ETH_DEBUG
total += le.size();
#endif
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j], n, h));
}
}
#if ETH_DEBUG
if (!total)
falsePos++;
#endif
}
}
#if ETH_DEBUG
cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves";
#endif
return ret;
doWork();
}

135
libethereum/Client.h

@ -40,9 +40,8 @@
#include "TransactionQueue.h"
#include "State.h"
#include "CommonNet.h"
#include "LogFilter.h"
#include "Miner.h"
#include "Interface.h"
#include "ClientBase.h"
namespace dev
{
@ -74,40 +73,6 @@ private:
static const int GenesisBlock = INT_MIN;
struct InstalledFilter
{
InstalledFilter(LogFilter const& _f): filter(_f) {}
LogFilter filter;
unsigned refCount = 1;
LocalisedLogEntries changes;
};
static const h256 PendingChangedFilter = u256(0);
static const h256 ChainChangedFilter = u256(1);
static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes());
static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0);
struct ClientWatch
{
ClientWatch(): lastPoll(std::chrono::system_clock::now()) {}
explicit ClientWatch(h256 _id, Reaping _r): id(_id), lastPoll(_r == Reaping::Automatic ? std::chrono::system_clock::now() : std::chrono::system_clock::time_point::max()) {}
h256 id;
LocalisedLogEntries changes = LocalisedLogEntries{ InitialChange };
mutable std::chrono::system_clock::time_point lastPoll = std::chrono::system_clock::now();
};
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; };
#define cwatch dev::LogOutputStream<dev::eth::WatchChannel, true>()
struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; };
struct WorkOutChannel: public LogChannel { static const char* name() { return "<W<"; } static const int verbosity = 16; };
struct WorkChannel: public LogChannel { static const char* name() { return "-W-"; } static const int verbosity = 16; };
#define cwork dev::LogOutputStream<dev::eth::WorkChannel, true>()
#define cworkin dev::LogOutputStream<dev::eth::WorkInChannel, true>()
#define cworkout dev::LogOutputStream<dev::eth::WorkOutChannel, true>()
template <class T> struct ABISerialiser {};
template <unsigned N> struct ABISerialiser<FixedHash<N>> { static bytes serialise(FixedHash<N> const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } };
template <> struct ABISerialiser<u256> { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } };
@ -182,7 +147,7 @@ private:
/**
* @brief Main API hub for interfacing with Ethereum.
*/
class Client: public MinerHost, public Interface, Worker
class Client: public MinerHost, public ClientBase, Worker
{
friend class Miner;
@ -211,88 +176,20 @@ public:
/// Resets the gas pricer to some other object.
void setGasPricer(std::shared_ptr<GasPricer> _gp) { m_gp = _gp; }
/// Submits the given message-call transaction.
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
/// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through).
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
/// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly.
virtual void inject(bytesConstRef _rlp) override;
virtual void inject(bytesConstRef _rlp);
/// Blocks until all pending transactions have been processed.
virtual void flushTransactions() override;
/// Makes the given call. Nothing is recorded into the state.
virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override;
/// Does the given creation. Nothing is recorded into the state.
/// @returns the pair of the Address of the created contract together with its code.
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override;
using Interface::call; // to remove warning about hiding virtual function
/// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH.
ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether);
// Informational stuff
// [NEW API]
using Interface::balanceAt;
using Interface::countAt;
using Interface::stateAt;
using Interface::codeAt;
using Interface::storageAt;
virtual u256 balanceAt(Address _a, BlockNumber _block) const;
virtual u256 countAt(Address _a, BlockNumber _block) const;
virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const;
virtual bytes codeAt(Address _a, BlockNumber _block) const;
virtual std::map<u256, u256> storageAt(Address _a, BlockNumber _block) const;
virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override;
virtual unsigned installWatch(h256 _filterId, Reaping _r = Reaping::Automatic) override;
virtual bool uninstallWatch(unsigned _watchId) override;
virtual LocalisedLogEntries peekWatch(unsigned _watchId) const;
virtual LocalisedLogEntries checkWatch(unsigned _watchId);
virtual LocalisedLogEntries logs(unsigned _watchId) const;
virtual LocalisedLogEntries logs(LogFilter const& _filter) const;
// [EXTRA API]:
/// @returns the length of the chain.
virtual unsigned number() const { return m_bc.number(); }
/// Get the list of pending transactions.
/// @TODO: Remove in favour of transactions().
virtual Transactions pending() const { return m_postMine.pending(); }
virtual h256 hashFromNumber(unsigned _number) const { return m_bc.numberHash(_number); }
virtual BlockInfo blockInfo(h256 _hash) const { return BlockInfo(m_bc.block(_hash)); }
virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); }
virtual Transaction transaction(h256 _transactionHash) const;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const;
virtual unsigned transactionCount(h256 _blockHash) const;
virtual unsigned uncleCount(h256 _blockHash) const;
virtual Transactions transactions(h256 _blockHash) const;
virtual TransactionHashes transactionHashes(h256 _blockHash) const;
/// Differences between transactions.
using Interface::diff;
virtual StateDiff diff(unsigned _txi, h256 _block) const;
virtual StateDiff diff(unsigned _txi, BlockNumber _block) const;
/// Get a list of all active addresses.
using Interface::addresses;
virtual std::vector<Address> addresses(BlockNumber _block) const;
/// Get the remaining gas limit in this block.
virtual u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); }
// [PRIVATE API - only relevant for base clients, not available in general]
dev::eth::State state(unsigned _txi, h256 _block) const;
dev::eth::State state(h256 _block) const;
dev::eth::State state(unsigned _txi) const;
@ -317,10 +214,6 @@ public:
/// Enable/disable fast mining.
void setTurboMining(bool _enable = true) { m_turboMining = _enable; }
/// Set the coinbase address.
virtual void setAddress(Address _us) { m_preMine.setAddress(_us); }
/// Get the coinbase address.
virtual Address address() const { return m_preMine.address(); }
/// Stops mining and sets the number of mining threads (0 for automatic).
virtual void setMiningThreads(unsigned _threads = 0);
/// Get the effective number of mining threads.
@ -356,6 +249,17 @@ public:
void killChain();
protected:
/// InterfaceStub methods
virtual BlockChain const& bc() const override { return m_bc; }
/// Returns the state object for the full block (i.e. the terminal state) for index _h.
/// Works properly with LatestBlock and PendingBlock.
using ClientBase::asOf;
virtual State asOf(h256 const& _block) const override;
virtual State preMine() const override { ReadGuard l(x_stateDB); return m_preMine; }
virtual State postMine() const override { ReadGuard l(x_stateDB); return m_postMine; }
virtual void prepareForTransaction() override;
/// Collate the changed filters for the bloom filter of the given pending transaction.
/// Insert any filters that are activated into @a o_changed.
void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _sha3);
@ -380,13 +284,8 @@ private:
virtual bool turbo() const { return m_turboMining; }
virtual bool force() const { return m_forceMining; }
/// Returns the state object for the full block (i.e. the terminal state) for index _h.
/// Works properly with LatestBlock and PendingBlock.
State asOf(unsigned _h) const;
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
CanonBlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
@ -407,10 +306,6 @@ private:
bool m_forceMining = false; ///< Mine even when there are no transactions pending?
bool m_verifyOwnBlocks = true; ///< Should be verify blocks that we mined?
mutable Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;
mutable std::chrono::system_clock::time_point m_lastGarbageCollection;
};

402
libethereum/ClientBase.cpp

@ -0,0 +1,402 @@
/*
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 ClientBase.cpp
* @author Gav Wood <i@gavwood.com>
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <libdevcore/StructuredLogger.h>
#include "ClientBase.h"
#include "BlockChain.h"
#include "Executive.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
State ClientBase::asOf(BlockNumber _h) const
{
if (_h == PendingBlock)
return postMine();
else if (_h == LatestBlock)
return preMine();
return asOf(bc().numberHash(_h));
}
void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
prepareForTransaction();
u256 n = postMine().transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
m_tq.attemptImport(t.rlp());
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged());
cnote << "New transaction " << t;
}
Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
prepareForTransaction();
u256 n = postMine().transactionsFrom(toAddress(_secret));
Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
m_tq.attemptImport(t.rlp());
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged());
cnote << "New transaction " << t;
return right160(sha3(rlpList(t.sender(), t.nonce())));
}
// TODO: remove try/catch, allow exceptions
ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber)
{
ExecutionResult ret;
try
{
State temp = asOf(_blockNumber);
u256 n = temp.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
ret = temp.execute(bc(), t.rlp(), Permanence::Reverted);
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
return ret;
}
ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber)
{
ExecutionResult ret;
try
{
State temp = asOf(_blockNumber);
u256 n = temp.transactionsFrom(toAddress(_secret));
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _data, n, _secret);
ret = temp.execute(bc(), t.rlp(), Permanence::Reverted);
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
return ret;
}
u256 ClientBase::balanceAt(Address _a, BlockNumber _block) const
{
return asOf(_block).balance(_a);
}
u256 ClientBase::countAt(Address _a, BlockNumber _block) const
{
return asOf(_block).transactionsFrom(_a);
}
u256 ClientBase::stateAt(Address _a, u256 _l, BlockNumber _block) const
{
return asOf(_block).storage(_a, _l);
}
bytes ClientBase::codeAt(Address _a, BlockNumber _block) const
{
return asOf(_block).code(_a);
}
map<u256, u256> ClientBase::storageAt(Address _a, BlockNumber _block) const
{
return asOf(_block).storage(_a);
}
// TODO: remove try/catch, allow exceptions
LocalisedLogEntries ClientBase::logs(unsigned _watchId) const
{
LogFilter f;
try
{
Guard l(x_filtersWatches);
f = m_filters.at(m_watches.at(_watchId).id).filter;
}
catch (...)
{
return LocalisedLogEntries();
}
return logs(f);
}
LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const
{
LocalisedLogEntries ret;
unsigned begin = min<unsigned>(bc().number() + 1, (unsigned)_f.latest());
unsigned end = min(bc().number(), min(begin, (unsigned)_f.earliest()));
// Handle pending transactions differently as they're not on the block chain.
if (begin > bc().number())
{
State temp = postMine();
for (unsigned i = 0; i < temp.pending().size(); ++i)
{
// Might have a transaction that contains a matching log.
TransactionReceipt const& tr = temp.receipt(i);
auto th = temp.pending()[i].sha3();
LogEntries le = _f.matches(tr);
if (le.size())
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, th));
}
begin = bc().number();
}
set<unsigned> matchingBlocks;
for (auto const& i: _f.bloomPossibilities())
for (auto u: bc().withBlockBloom(i, end, begin))
matchingBlocks.insert(u);
unsigned falsePos = 0;
for (auto n: matchingBlocks)
{
int total = 0;
auto h = bc().numberHash(n);
auto receipts = bc().receipts(h).receipts;
for (size_t i = 0; i < receipts.size(); i++)
{
TransactionReceipt receipt = receipts[i];
if (_f.matches(receipt.bloom()))
{
auto info = bc().info(h);
auto th = transaction(info.hash, i).sha3();
LogEntries le = _f.matches(receipt);
if (le.size())
{
total += le.size();
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j], n, th));
}
}
if (!total)
falsePos++;
}
}
cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves";
return ret;
}
unsigned ClientBase::installWatch(LogFilter const& _f, Reaping _r)
{
h256 h = _f.sha3();
{
Guard l(x_filtersWatches);
if (!m_filters.count(h))
{
cwatch << "FFF" << _f << h.abridged();
m_filters.insert(make_pair(h, _f));
}
}
return installWatch(h, _r);
}
unsigned ClientBase::installWatch(h256 _h, Reaping _r)
{
unsigned ret;
{
Guard l(x_filtersWatches);
ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0;
m_watches[ret] = ClientWatch(_h, _r);
cwatch << "+++" << ret << _h.abridged();
}
auto ch = logs(ret);
if (ch.empty())
ch.push_back(InitialChange);
{
Guard l(x_filtersWatches);
swap(m_watches[ret].changes, ch);
}
return ret;
}
bool ClientBase::uninstallWatch(unsigned _i)
{
cwatch << "XXX" << _i;
Guard l(x_filtersWatches);
auto it = m_watches.find(_i);
if (it == m_watches.end())
return false;
auto id = it->second.id;
m_watches.erase(it);
auto fit = m_filters.find(id);
if (fit != m_filters.end())
if (!--fit->second.refCount)
{
cwatch << "*X*" << fit->first << ":" << fit->second.filter;
m_filters.erase(fit);
}
return true;
}
LocalisedLogEntries ClientBase::peekWatch(unsigned _watchId) const
{
Guard l(x_filtersWatches);
cwatch << "peekWatch" << _watchId;
auto& w = m_watches.at(_watchId);
cwatch << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
w.lastPoll = chrono::system_clock::now();
return w.changes;
}
LocalisedLogEntries ClientBase::checkWatch(unsigned _watchId)
{
Guard l(x_filtersWatches);
LocalisedLogEntries ret;
cwatch << "checkWatch" << _watchId;
auto& w = m_watches.at(_watchId);
cwatch << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
std::swap(ret, w.changes);
w.lastPoll = chrono::system_clock::now();
return ret;
}
h256 ClientBase::hashFromNumber(unsigned _number) const
{
return bc().numberHash(_number);
}
BlockInfo ClientBase::blockInfo(h256 _hash) const
{
return BlockInfo(bc().block(_hash));
}
BlockDetails ClientBase::blockDetails(h256 _hash) const
{
return bc().details(_hash);
}
Transaction ClientBase::transaction(h256 _transactionHash) const
{
return Transaction(bc().transaction(_transactionHash), CheckSignature::Range);
}
Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const
{
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[1].itemCount())
return Transaction(b[1][_i].data(), CheckSignature::Range);
else
return Transaction();
}
Transactions ClientBase::transactions(h256 _blockHash) const
{
auto bl = bc().block(_blockHash);
RLP b(bl);
Transactions res;
for (unsigned i = 0; i < b[1].itemCount(); i++)
res.emplace_back(b[1][i].data(), CheckSignature::Range);
return res;
}
TransactionHashes ClientBase::transactionHashes(h256 _blockHash) const
{
return bc().transactionHashes(_blockHash);
}
BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const
{
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data());
else
return BlockInfo();
}
UncleHashes ClientBase::uncleHashes(h256 _blockHash) const
{
return bc().uncleHashes(_blockHash);
}
unsigned ClientBase::transactionCount(h256 _blockHash) const
{
auto bl = bc().block(_blockHash);
RLP b(bl);
return b[1].itemCount();
}
unsigned ClientBase::uncleCount(h256 _blockHash) const
{
auto bl = bc().block(_blockHash);
RLP b(bl);
return b[2].itemCount();
}
unsigned ClientBase::number() const
{
return bc().number();
}
Transactions ClientBase::pending() const
{
return postMine().pending();
}
StateDiff ClientBase::diff(unsigned _txi, h256 _block) const
{
State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
StateDiff ClientBase::diff(unsigned _txi, BlockNumber _block) const
{
State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
Addresses ClientBase::addresses(BlockNumber _block) const
{
Addresses ret;
for (auto const& i: asOf(_block).addresses())
ret.push_back(i.first);
return ret;
}
u256 ClientBase::gasLimitRemaining() const
{
return postMine().gasLimitRemaining();
}
void ClientBase::setAddress(Address _us)
{
preMine().setAddress(_us);
}
Address ClientBase::address() const
{
return preMine().address();
}

167
libethereum/ClientBase.h

@ -0,0 +1,167 @@
/*
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 ClientBase.h
* @author Gav Wood <i@gavwood.com>
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <chrono>
#include "Interface.h"
#include "LogFilter.h"
namespace dev {
namespace eth {
struct InstalledFilter
{
InstalledFilter(LogFilter const& _f): filter(_f) {}
LogFilter filter;
unsigned refCount = 1;
LocalisedLogEntries changes;
};
static const h256 PendingChangedFilter = u256(0);
static const h256 ChainChangedFilter = u256(1);
static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes());
static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0);
struct ClientWatch
{
ClientWatch(): lastPoll(std::chrono::system_clock::now()) {}
explicit ClientWatch(h256 _id, Reaping _r): id(_id), lastPoll(_r == Reaping::Automatic ? std::chrono::system_clock::now() : std::chrono::system_clock::time_point::max()) {}
h256 id;
LocalisedLogEntries changes = LocalisedLogEntries{ InitialChange };
mutable std::chrono::system_clock::time_point lastPoll = std::chrono::system_clock::now();
};
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; };
#define cwatch dev::LogOutputStream<dev::eth::WatchChannel, true>()
struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; };
struct WorkOutChannel: public LogChannel { static const char* name() { return "<W<"; } static const int verbosity = 16; };
struct WorkChannel: public LogChannel { static const char* name() { return "-W-"; } static const int verbosity = 16; };
#define cwork dev::LogOutputStream<dev::eth::WorkChannel, true>()
#define cworkin dev::LogOutputStream<dev::eth::WorkInChannel, true>()
#define cworkout dev::LogOutputStream<dev::eth::WorkOutChannel, true>()
class ClientBase: public dev::eth::Interface
{
public:
ClientBase() {}
virtual ~ClientBase() {}
/// Submits the given message-call transaction.
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
/// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through).
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
/// Makes the given call. Nothing is recorded into the state.
virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override;
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override;
using Interface::balanceAt;
using Interface::countAt;
using Interface::stateAt;
using Interface::codeAt;
using Interface::storageAt;
virtual u256 balanceAt(Address _a, BlockNumber _block) const override;
virtual u256 countAt(Address _a, BlockNumber _block) const override;
virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override;
virtual bytes codeAt(Address _a, BlockNumber _block) const override;
virtual std::map<u256, u256> storageAt(Address _a, BlockNumber _block) const override;
virtual LocalisedLogEntries logs(unsigned _watchId) const override;
virtual LocalisedLogEntries logs(LogFilter const& _filter) const override;
/// Install, uninstall and query watches.
virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override;
virtual unsigned installWatch(h256 _filterId, Reaping _r = Reaping::Automatic) override;
virtual bool uninstallWatch(unsigned _watchId) override;
virtual LocalisedLogEntries peekWatch(unsigned _watchId) const override;
virtual LocalisedLogEntries checkWatch(unsigned _watchId) override;
virtual h256 hashFromNumber(unsigned _number) const override;
virtual eth::BlockInfo blockInfo(h256 _hash) const override;
virtual eth::BlockDetails blockDetails(h256 _hash) const override;
virtual eth::Transaction transaction(h256 _transactionHash) const override;
virtual eth::Transaction transaction(h256 _blockHash, unsigned _i) const override;
virtual eth::Transactions transactions(h256 _blockHash) const override;
virtual eth::TransactionHashes transactionHashes(h256 _blockHash) const override;
virtual eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override;
virtual eth::UncleHashes uncleHashes(h256 _blockHash) const override;
virtual unsigned transactionCount(h256 _blockHash) const override;
virtual unsigned uncleCount(h256 _blockHash) const override;
virtual unsigned number() const override;
virtual eth::Transactions pending() const override;
using Interface::diff;
virtual StateDiff diff(unsigned _txi, h256 _block) const override;
virtual StateDiff diff(unsigned _txi, BlockNumber _block) const override;
using Interface::addresses;
virtual Addresses addresses(BlockNumber _block) const override;
virtual u256 gasLimitRemaining() const override;
/// Set the coinbase address
virtual void setAddress(Address _us) override;
/// Get the coinbase address
virtual Address address() const override;
/// TODO: consider moving it to a separate interface
virtual void setMiningThreads(unsigned _threads) override { (void)_threads; BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::setMiningThreads")); }
virtual unsigned miningThreads() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningThreads")); }
virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); }
virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); }
virtual bool isMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); }
virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); }
virtual std::pair<h256, u256> getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); }
virtual bool submitWork(eth::ProofOfWork::Proof const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); }
State asOf(BlockNumber _h) const;
protected:
/// The interface that must be implemented in any class deriving this.
/// {
virtual BlockChain const& bc() const = 0;
virtual State asOf(h256 const& _h) const = 0;
virtual State preMine() const = 0;
virtual State postMine() const = 0;
virtual void prepareForTransaction() = 0;
/// }
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
// filters
mutable Mutex x_filtersWatches; ///< Our lock.
std::map<h256, InstalledFilter> m_filters; ///< The dictionary of filters that are active.
std::map<unsigned, ClientWatch> m_watches; ///< Each and every watch - these reference a filter.
};
}}

5
libethereum/Executive.cpp

@ -44,6 +44,11 @@ u256 Executive::gasUsed() const
return m_t.gas() - m_endGas;
}
ExecutionResult Executive::executionResult() const
{
return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit, m_ext ? m_ext->sub.refunds : 0);
}
void Executive::accrueSubState(SubState& _parentContext)
{
if (m_ext)

2
libethereum/Executive.h

@ -104,7 +104,7 @@ public:
bool excepted() const { return m_excepted != TransactionException::None; }
/// Get the above in an amalgamated fashion.
ExecutionResult executionResult() const { return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit); }
ExecutionResult executionResult() const;
private:
bool setup();

6
libethereum/Interface.h

@ -38,6 +38,7 @@ namespace eth
{
using TransactionHashes = h256s;
using UncleHashes = h256s;
enum class Reaping
{
@ -66,9 +67,6 @@ public:
/// @returns the new contract's address (assuming it all goes through).
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0;
/// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly.
virtual void inject(bytesConstRef _rlp) = 0;
/// Blocks until all pending transactions have been processed.
virtual void flushTransactions() = 0;
@ -118,6 +116,7 @@ public:
virtual Transaction transaction(h256 _transactionHash) const = 0;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0;
virtual UncleHashes uncleHashes(h256 _blockHash) const = 0;
virtual unsigned transactionCount(h256 _blockHash) const = 0;
virtual unsigned uncleCount(h256 _blockHash) const = 0;
virtual Transactions transactions(h256 _blockHash) const = 0;
@ -138,6 +137,7 @@ public:
virtual StateDiff diff(unsigned _txi, BlockNumber _block) const = 0;
/// Get a list of all active addresses.
/// NOTE: This only works when compiled with ETH_FATDB; otherwise will throw InterfaceNotSupported.
virtual Addresses addresses() const { return addresses(m_default); }
virtual Addresses addresses(BlockNumber _block) const = 0;

4
libethereum/State.cpp

@ -342,6 +342,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
map<Address, u256> State::addresses() const
{
#if ETH_FATDB
map<Address, u256> ret;
for (auto i: m_cache)
if (i.second.isAlive())
@ -350,6 +351,9 @@ map<Address, u256> State::addresses() const
if (m_cache.find(i.first) == m_cache.end())
ret[i.first] = RLP(i.second)[1].toInt<u256>();
return ret;
#else
throw InterfaceNotSupported("State::addresses()");
#endif
}
void State::resetCurrent()

4
libethereum/State.h

@ -41,7 +41,7 @@
namespace dev
{
namespace test { class ImportTest; }
namespace test { class ImportTest; class StateLoader; }
namespace eth
{
@ -99,6 +99,7 @@ class State
{
friend class ExtVM;
friend class dev::test::ImportTest;
friend class dev::test::StateLoader;
friend class Executive;
public:
@ -127,6 +128,7 @@ public:
OverlayDB const& db() const { return m_db; }
/// @returns the set containing all addresses currently in use in Ethereum.
/// @throws InterfaceNotSupported if compiled without ETH_FATDB.
std::map<Address, u256> addresses() const;
/// Get the header information on the present block.

4
libethereum/Transaction.cpp

@ -68,6 +68,10 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig)
m_type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall;
m_receiveAddress = rlp[field = 3].isEmpty() ? Address() : rlp[field = 3].toHash<Address>(RLP::VeryStrict);
m_value = rlp[field = 4].toInt<u256>();
if (!rlp[field = 5].isData())
BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction data RLP must be an array"));
m_data = rlp[field = 5].toBytes();
byte v = rlp[field = 6].toInt<byte>() - 27;
h256 r = rlp[field = 7].toInt<u256>();

3
libethereum/Transaction.h

@ -75,12 +75,13 @@ TransactionException toTransactionException(VMException const& _e);
struct ExecutionResult
{
ExecutionResult() = default;
ExecutionResult(u256 _gasUsed, TransactionException _excepted, Address _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit): gasUsed(_gasUsed), excepted(_excepted), newAddress(_newAddress), output(_output.toBytes()), codeDeposit(_codeDeposit) {}
ExecutionResult(u256 _gasUsed, TransactionException _excepted, Address _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit, u256 _gasRefund): gasUsed(_gasUsed), excepted(_excepted), newAddress(_newAddress), output(_output.toBytes()), codeDeposit(_codeDeposit), gasRefunded(_gasRefund) {}
u256 gasUsed = 0;
TransactionException excepted = TransactionException::Unknown;
Address newAddress;
bytes output;
CodeDeposit codeDeposit = CodeDeposit::None;
u256 gasRefunded = 0;
};
std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er);

2
libp2p/RLPxHandshake.h

@ -95,7 +95,7 @@ protected:
void transition(boost::system::error_code _ech = boost::system::error_code());
/// Timeout for remote to respond to transition events. Enforced by m_idleTimer and refreshed by transition().
boost::posix_time::milliseconds const c_timeout = boost::posix_time::milliseconds(1000);
boost::posix_time::milliseconds const c_timeout = boost::posix_time::milliseconds(1800);
State m_nextState = New; ///< Current or expected state of transition.
bool m_cancel = false; ///< Will be set to true if connection was canceled.

9
libp2p/UDP.h

@ -163,7 +163,14 @@ void UDPSocket<Handler, MaxDatagramSize>::connect()
return;
m_socket.open(bi::udp::v4());
m_socket.bind(m_endpoint);
try
{
m_socket.bind(m_endpoint);
}
catch (...)
{
m_socket.bind(bi::udp::endpoint(bi::udp::v4(), m_endpoint.port()));
}
// clear write queue so reconnect doesn't send stale messages
Guard l(x_sendQ);

1
libsolidity/ExpressionCompiler.h

@ -42,7 +42,6 @@ class CompilerContext;
class Type;
class IntegerType;
class ArrayType;
class StaticStringType;
/**
* Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream

13
libsolidity/Token.h

@ -143,7 +143,6 @@ namespace solidity
\
/* Keywords */ \
K(Break, "break", 0) \
K(Case, "case", 0) \
K(Const, "constant", 0) \
K(Anonymous, "anonymous", 0) \
K(Continue, "continue", 0) \
@ -168,7 +167,6 @@ namespace solidity
K(Return, "return", 0) \
K(Returns, "returns", 0) \
K(Struct, "struct", 0) \
K(Switch, "switch", 0) \
K(Var, "var", 0) \
K(While, "while", 0) \
K(Enum, "enum", 0) \
@ -290,7 +288,6 @@ namespace solidity
K(Byte, "byte", 0) \
K(Address, "address", 0) \
K(Bool, "bool", 0) \
K(StringType, "string", 0) \
K(Real, "real", 0) \
K(UReal, "ureal", 0) \
T(TypesEnd, NULL, 0) /* used as type enum end marker */ \
@ -306,6 +303,16 @@ namespace solidity
/* Identifiers (not keywords or future reserved words). */ \
T(Identifier, NULL, 0) \
\
/* Keywords reserved for future. use*/ \
T(String, "string", 0) \
K(Case, "case", 0) \
K(Switch, "switch", 0) \
K(Throw, "throw", 0) \
K(Try, "try", 0) \
K(Catch, "catch", 0) \
K(Using, "using", 0) \
K(Type, "type", 0) \
K(TypeOf, "typeof", 0) \
/* Illegal token - not able to scan. */ \
T(Illegal, "ILLEGAL", 0) \
\

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;
};
}
}

31
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -47,10 +47,17 @@ using namespace jsonrpc;
using namespace dev;
using namespace dev::eth;
#if ETH_DEBUG
const unsigned dev::SensibleHttpThreads = 1;
#else
const unsigned dev::SensibleHttpThreads = 4;
#endif
const unsigned dev::SensibleHttpPort = 8080;
static Json::Value toJson(dev::eth::BlockInfo const& _bi)
{
Json::Value res;
res["hash"] = boost::lexical_cast<string>(_bi.hash);
res["hash"] = toJS(_bi.hash);
res["parentHash"] = toJS(_bi.parentHash);
res["sha3Uncles"] = toJS(_bi.sha3Uncles);
res["miner"] = toJS(_bi.coinbaseAddress);
@ -58,10 +65,12 @@ static Json::Value toJson(dev::eth::BlockInfo const& _bi)
res["transactionsRoot"] = toJS(_bi.transactionsRoot);
res["difficulty"] = toJS(_bi.difficulty);
res["number"] = toJS(_bi.number);
res["gasUsed"] = toJS(_bi.gasUsed);
res["gasLimit"] = toJS(_bi.gasLimit);
res["timestamp"] = toJS(_bi.timestamp);
res["extraData"] = toJS(_bi.extraData);
res["nonce"] = toJS(_bi.nonce);
res["logsBloom"] = toJS(_bi.logBloom);
return res;
}
@ -79,18 +88,24 @@ static Json::Value toJson(dev::eth::Transaction const& _t)
return res;
}
static Json::Value toJson(dev::eth::BlockInfo const& _bi, Transactions const& _ts)
static Json::Value toJson(dev::eth::BlockInfo const& _bi, UncleHashes const& _us, Transactions const& _ts)
{
Json::Value res = toJson(_bi);
res["uncles"] = Json::Value(Json::arrayValue);
for (h256 h: _us)
res["uncles"].append(toJS(h));
res["transactions"] = Json::Value(Json::arrayValue);
for (Transaction const& t: _ts)
res["transactions"].append(toJson(t));
return res;
}
static Json::Value toJson(dev::eth::BlockInfo const& _bi, TransactionHashes const& _ts)
static Json::Value toJson(dev::eth::BlockInfo const& _bi, UncleHashes const& _us, TransactionHashes const& _ts)
{
Json::Value res = toJson(_bi);
res["uncles"] = Json::Value(Json::arrayValue);
for (h256 h: _us)
res["uncles"].append(toJS(h));
res["transactions"] = Json::Value(Json::arrayValue);
for (h256 const& t: _ts)
res["transactions"].append(toJS(t));
@ -387,7 +402,7 @@ string WebThreeStubServerBase::eth_getCode(string const& _address, string const&
{
try
{
return toJS(client()->codeAt(jsToAddress(_address), toBlockNumber(_blockNumber)));
return toJS(client()->codeAt(jsToAddress(_address), toBlockNumber(_blockNumber)), 1);
}
catch (...)
{
@ -498,9 +513,9 @@ Json::Value WebThreeStubServerBase::eth_getBlockByHash(string const& _blockHash,
{
auto h = jsToFixed<32>(_blockHash);
if (_includeTransactions)
return toJson(client()->blockInfo(h), client()->transactions(h));
return toJson(client()->blockInfo(h), client()->uncleHashes(h), client()->transactions(h));
else
return toJson(client()->blockInfo(h), client()->transactionHashes(h));
return toJson(client()->blockInfo(h), client()->uncleHashes(h), client()->transactionHashes(h));
}
catch (...)
{
@ -514,9 +529,9 @@ Json::Value WebThreeStubServerBase::eth_getBlockByNumber(string const& _blockNum
{
auto h = client()->hashFromNumber(jsToInt(_blockNumber));
if (_includeTransactions)
return toJson(client()->blockInfo(h), client()->transactions(h));
return toJson(client()->blockInfo(h), client()->uncleHashes(h), client()->transactions(h));
else
return toJson(client()->blockInfo(h), client()->transactionHashes(h));
return toJson(client()->blockInfo(h), client()->uncleHashes(h), client()->transactionHashes(h));
}
catch (...)
{

3
libweb3jsonrpc/WebThreeStubServerBase.h

@ -48,6 +48,9 @@ namespace shh
class Interface;
}
extern const unsigned SensibleHttpThreads;
extern const unsigned SensibleHttpPort;
class WebThreeStubDatabaseFace
{
public:

4
mix/ClientModel.cpp

@ -350,6 +350,10 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
CompiledContract const* contract = contracts[s.codeIndex];
AssemblyItem const& instruction = codeItems[s.codeIndex][instructionIndex];
std::stringstream str;
str << instruction.getLocation().sourceName;
qDebug() << QString::fromStdString(str.str());
if (instruction.type() == dev::eth::Push && !instruction.data())
{
//register new local variable initialization

318
mix/MixClient.cpp

@ -45,29 +45,20 @@ namespace mix
const Secret c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
const u256 c_mixGenesisDifficulty = c_minimumDifficulty; //TODO: make it lower for Mix somehow
class MixBlockChain: public dev::eth::BlockChain
bytes MixBlockChain::createGenesisBlock(h256 _stateRoot)
{
public:
MixBlockChain(std::string const& _path, h256 _stateRoot):
BlockChain(createGenesisBlock(_stateRoot), _path, true)
{
}
static bytes createGenesisBlock(h256 _stateRoot)
{
RLPStream block(3);
block.appendList(15)
<< h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie
<< LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0
<< std::string() << h256() << h64(u64(42));
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
};
RLPStream block(3);
block.appendList(15)
<< h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie
<< LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0
<< std::string() << h256() << h64(u64(42));
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
}
MixClient::MixClient(std::string const& _dbPath):
m_dbPath(_dbPath), m_minigThreads(0)
m_dbPath(_dbPath), m_miningThreads(0)
{
std::map<Secret, u256> account;
account.insert(std::make_pair(c_defaultUserAccountSecret, 1000000 * ether));
@ -81,7 +72,7 @@ MixClient::~MixClient()
void MixClient::resetState(std::map<Secret, u256> _accounts)
{
WriteGuard l(x_state);
Guard fl(m_filterLock);
Guard fl(x_filtersWatches);
m_filters.clear();
m_watches.clear();
@ -198,7 +189,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
// collect watches
h256Set changed;
Guard l(m_filterLock);
Guard l(x_filtersWatches);
for (std::pair<h256 const, eth::InstalledFilter>& i: m_filters)
if ((unsigned)i.second.filter.latest() > bc().number())
{
@ -273,26 +264,11 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons
return address;
}
void MixClient::inject(bytesConstRef _rlp)
{
WriteGuard l(x_state);
eth::Transaction t(_rlp, CheckSignature::None);
executeTransaction(t, m_state, false);
}
void MixClient::flushTransactions()
{
}
dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber)
{
u256 n;
State temp;
{
ReadGuard lr(x_state);
temp = asOf(_blockNumber);
n = temp.transactionsFrom(toAddress(_secret));
}
State temp = asOf(_blockNumber);
u256 n = temp.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
bytes rlp = t.rlp();
WriteGuard lw(x_state); //TODO: lock is required only for last execution state
@ -316,122 +292,6 @@ dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes c
return lastExecution().result;
}
u256 MixClient::balanceAt(Address _a, BlockNumber _block) const
{
return asOf(_block).balance(_a);
}
u256 MixClient::countAt(Address _a, BlockNumber _block) const
{
return asOf(_block).transactionsFrom(_a);
}
u256 MixClient::stateAt(Address _a, u256 _l, BlockNumber _block) const
{
return asOf(_block).storage(_a, _l);
}
bytes MixClient::codeAt(Address _a, BlockNumber _block) const
{
return asOf(_block).code(_a);
}
std::map<u256, u256> MixClient::storageAt(Address _a, BlockNumber _block) const
{
return asOf(_block).storage(_a);
}
eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const
{
Guard l(m_filterLock);
h256 h = m_watches.at(_watchId).id;
auto filterIter = m_filters.find(h);
if (filterIter != m_filters.end())
return logs(filterIter->second.filter);
return eth::LocalisedLogEntries();
}
eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const
{
LocalisedLogEntries ret;
unsigned lastBlock = bc().number();
unsigned block = std::min<unsigned>(lastBlock, (unsigned)_f.latest());
unsigned end = std::min(lastBlock, std::min(block, (unsigned)_f.earliest()));
// Pending transactions
if (block > bc().number())
{
ReadGuard l(x_state);
for (unsigned i = 0; i < m_state.pending().size(); ++i)
{
// Might have a transaction that contains a matching log.
TransactionReceipt const& tr = m_state.receipt(i);
LogEntries logEntries = _f.matches(tr);
for (unsigned entry = 0; entry < logEntries.size(); ++entry)
ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block));
}
block = bc().number();
}
// The rest
auto h = bc().numberHash(block);
for (; ret.size() != block && block != end; block--)
{
if (_f.matches(bc().info(h).logBloom))
for (TransactionReceipt receipt: bc().receipts(h).receipts)
if (_f.matches(receipt.bloom()))
for (auto const& e: _f.matches(receipt))
ret.insert(ret.begin(), LocalisedLogEntry(e, block));
h = bc().details(h).parent;
}
return ret;
}
unsigned MixClient::installWatch(h256 _h, eth::Reaping _r)
{
unsigned ret;
{
Guard l(m_filterLock);
ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0;
m_watches[ret] = ClientWatch(_h, _r);
}
auto ch = logs(ret);
if (ch.empty())
ch.push_back(eth::InitialChange);
{
Guard l(m_filterLock);
swap(m_watches[ret].changes, ch);
}
return ret;
}
unsigned MixClient::installWatch(eth::LogFilter const& _f, eth::Reaping _r)
{
h256 h = _f.sha3();
{
Guard l(m_filterLock);
m_filters.insert(std::make_pair(h, _f));
}
return installWatch(h, _r);
}
bool MixClient::uninstallWatch(unsigned _i)
{
Guard l(m_filterLock);
auto it = m_watches.find(_i);
if (it == m_watches.end())
return false;
auto id = it->second.id;
m_watches.erase(it);
auto fit = m_filters.find(id);
if (fit != m_filters.end())
if (!--fit->second.refCount)
m_filters.erase(fit);
return true;
}
void MixClient::noteChanged(h256Set const& _filters)
{
for (auto& i: m_watches)
@ -446,168 +306,26 @@ void MixClient::noteChanged(h256Set const& _filters)
i.second.changes.clear();
}
LocalisedLogEntries MixClient::peekWatch(unsigned _watchId) const
{
Guard l(m_filterLock);
if (_watchId < m_watches.size())
return m_watches.at(_watchId).changes;
return LocalisedLogEntries();
}
LocalisedLogEntries MixClient::checkWatch(unsigned _watchId)
{
Guard l(m_filterLock);
LocalisedLogEntries ret;
if (_watchId < m_watches.size())
std::swap(ret, m_watches.at(_watchId).changes);
return ret;
}
h256 MixClient::hashFromNumber(unsigned _number) const
{
ReadGuard l(x_state);
return bc().numberHash(_number);
}
eth::BlockInfo MixClient::blockInfo(h256 _hash) const
{
ReadGuard l(x_state);
return BlockInfo(bc().block(_hash));
}
eth::BlockInfo MixClient::blockInfo() const
{
ReadGuard l(x_state);
return BlockInfo(bc().block());
}
eth::BlockDetails MixClient::blockDetails(h256 _hash) const
{
ReadGuard l(x_state);
return bc().details(_hash);
}
Transaction MixClient::transaction(h256 _transactionHash) const
{
ReadGuard l(x_state);
return Transaction(bc().transaction(_transactionHash), CheckSignature::Range);
}
eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[1].itemCount())
return Transaction(b[1][_i].data(), CheckSignature::Range);
else
return Transaction();
}
eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data());
else
return BlockInfo();
}
unsigned MixClient::transactionCount(h256 _blockHash) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
return b[1].itemCount();
}
unsigned MixClient::uncleCount(h256 _blockHash) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
return b[2].itemCount();
}
Transactions MixClient::transactions(h256 _blockHash) const
{
ReadGuard l(x_state);
auto bl = bc().block(_blockHash);
RLP b(bl);
Transactions res;
for (unsigned i = 0; i < b[1].itemCount(); i++)
res.emplace_back(b[1][i].data(), CheckSignature::Range);
return res;
}
TransactionHashes MixClient::transactionHashes(h256 _blockHash) const
{
ReadGuard l(x_state);
return bc().transactionHashes(_blockHash);
}
unsigned MixClient::number() const
{
ReadGuard l(x_state);
return bc().number();
}
eth::Transactions MixClient::pending() const
{
ReadGuard l(x_state);
return m_state.pending();
}
eth::StateDiff MixClient::diff(unsigned _txi, h256 _block) const
{
ReadGuard l(x_state);
State st(m_stateDB, bc(), _block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
eth::StateDiff MixClient::diff(unsigned _txi, BlockNumber _block) const
{
State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
Addresses MixClient::addresses(BlockNumber _block) const
{
Addresses ret;
for (auto const& i: asOf(_block).addresses())
ret.push_back(i.first);
return ret;
}
u256 MixClient::gasLimitRemaining() const
{
ReadGuard l(x_state);
return m_state.gasLimitRemaining();
}
void MixClient::setAddress(Address _us)
{
WriteGuard l(x_state);
m_state.setAddress(_us);
}
Address MixClient::address() const
{
ReadGuard l(x_state);
return m_state.address();
}
void MixClient::setMiningThreads(unsigned _threads)
{
m_minigThreads = _threads;
m_miningThreads = _threads;
}
unsigned MixClient::miningThreads() const
{
return m_minigThreads;
return m_miningThreads;
}
void MixClient::startMining()

69
mix/MixClient.h

@ -25,8 +25,7 @@
#include <vector>
#include <string>
#include <libethcore/Common.h>
#include <libethereum/Interface.h>
#include <libethereum/ClientBase.h>
#include <libethereum/Client.h>
#include "MachineStates.h"
@ -35,9 +34,15 @@ namespace dev
namespace mix
{
class MixBlockChain;
class MixBlockChain: public dev::eth::BlockChain
{
public:
MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, true) {}
static bytes createGenesisBlock(h256 _stateRoot);
};
class MixClient: public dev::eth::Interface
class MixClient: public dev::eth::ClientBase
{
public:
MixClient(std::string const& _dbPath);
@ -48,43 +53,12 @@ public:
ExecutionResult lastExecution() const;
ExecutionResult execution(unsigned _index) const;
//dev::eth::Interface
void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override;
Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override;
void inject(bytesConstRef _rlp) override;
void flushTransactions() override;
dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber) override;
dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber) override;
u256 balanceAt(Address _a, eth::BlockNumber _block) const override;
u256 countAt(Address _a, eth::BlockNumber _block) const override;
u256 stateAt(Address _a, u256 _l, eth::BlockNumber _block) const override;
bytes codeAt(Address _a, eth::BlockNumber _block) const override;
std::map<u256, u256> storageAt(Address _a, eth::BlockNumber _block) const override;
eth::LocalisedLogEntries logs(unsigned _watchId) const override;
eth::LocalisedLogEntries logs(eth::LogFilter const& _filter) const override;
unsigned installWatch(eth::LogFilter const& _filter, eth::Reaping _r = eth::Reaping::Automatic) override;
unsigned installWatch(h256 _filterId, eth::Reaping _r = eth::Reaping::Automatic) override;
bool uninstallWatch(unsigned _watchId) override;
eth::LocalisedLogEntries peekWatch(unsigned _watchId) const override;
eth::LocalisedLogEntries checkWatch(unsigned _watchId) override;
h256 hashFromNumber(unsigned _number) const override;
eth::BlockInfo blockInfo(h256 _hash) const override;
eth::BlockDetails blockDetails(h256 _hash) const override;
eth::Transaction transaction(h256 _transactionHash) const override;
eth::Transaction transaction(h256 _blockHash, unsigned _i) const override;
eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override;
unsigned transactionCount(h256 _blockHash) const override;
unsigned uncleCount(h256 _blockHash) const override;
eth::Transactions transactions(h256 _blockHash) const override;
eth::TransactionHashes transactionHashes(h256 _blockHash) const override;
unsigned number() const override;
eth::Transactions pending() const override;
eth::StateDiff diff(unsigned _txi, h256 _block) const override;
eth::StateDiff diff(unsigned _txi, eth::BlockNumber _block) const override;
Addresses addresses(eth::BlockNumber _block) const override;
u256 gasLimitRemaining() const override;
dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock) override;
dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock) override;
void setAddress(Address _us) override;
Address address() const override;
void setMiningThreads(unsigned _threads) override;
unsigned miningThreads() const override;
void startMining() override;
@ -93,10 +67,24 @@ public:
eth::MineProgress miningProgress() const override;
std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); }
bool submitWork(eth::ProofOfWork::Proof const&) override { return false; }
virtual void flushTransactions() override {}
/// @returns the last mined block information
using Interface::blockInfo; // to remove warning about hiding virtual function
eth::BlockInfo blockInfo() const;
std::vector<KeyPair> userAccounts() { return m_userAccounts; }
protected:
virtual dev::eth::BlockChain& bc() { return *m_bc; }
/// InterfaceStub methods
virtual dev::eth::State asOf(h256 const& _block) const override;
using ClientBase::asOf;
virtual dev::eth::BlockChain const& bc() const override { return *m_bc; }
virtual dev::eth::State preMine() const override { ReadGuard l(x_state); return m_startState; }
virtual dev::eth::State postMine() const override { ReadGuard l(x_state); return m_state; }
virtual void prepareForTransaction() override {}
private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call);
void noteChanged(h256Set const& _filters);
@ -111,12 +99,9 @@ private:
std::auto_ptr<MixBlockChain> m_bc;
mutable boost::shared_mutex x_state;
mutable boost::shared_mutex x_executions;
mutable std::mutex m_filterLock;
std::map<h256, dev::eth::InstalledFilter> m_filters;
std::map<unsigned, dev::eth::ClientWatch> m_watches;
ExecutionResults m_executions;
std::string m_dbPath;
unsigned m_minigThreads;
unsigned m_miningThreads;
};
}

6
mix/qml/Debugger.qml

@ -40,7 +40,7 @@ Rectangle {
var errorInfo = ErrorLocationFormater.extractErrorInfo(compilationErrorMessage, false);
errorLocation.text = errorInfo.errorLocation;
errorDetail.text = errorInfo.errorDetail;
errorLine.text = errorInfo.errorLine;
errorLine.text = errorInfo.line;
}
function update(data, giveFocus)
@ -242,7 +242,6 @@ Rectangle {
height: 30
buttonShortcut: "Ctrl+Shift+F11"
buttonTooltip: qsTr("Step Out Back")
visible: false
}
StepActionImage
@ -315,9 +314,8 @@ Rectangle {
height: 30
buttonShortcut: "Ctrl+F5"
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 QtWebEngine 1.0
import QtWebEngine.experimental 1.0
import "js/ErrorLocationFormater.js" as ErrorLocationFormater
Item {
signal editorTextChanged
@ -83,7 +84,22 @@ Item {
runJavaScript("getTextChanged()", function(result) { });
pollTimer.running = true;
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();
}
}

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);
}
/* 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/anyword-hint.js"></script>
<script src="cm/closebrackets.js"></script>
<script src="cm/errorannotation.js"></script>
<script src="cm/tern.js"></script>
<script src="cm/acorn.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);
if (mac === true) {
editor.setOption("extraKeys", {
"Cmd-V": function(cm) {
cm.replaceSelection(clipboard);
},
"Cmd-X": function(cm) {
window.document.execCommand("cut");
},
"Cmd-C": function(cm) {
window.document.execCommand("copy");
}});
editor.setOption("extraKeys", {
"Cmd-V": function(cm) {
cm.replaceSelection(clipboard);
},
"Cmd-X": function(cm) {
window.document.execCommand("cut");
},
"Cmd-C": function(cm) {
window.document.execCommand("copy");
}});
}
makeMarker = function() {
var marker = document.createElement("div");
marker.style.color = "#822";
marker.innerHTML = "●";
return marker;
var marker = document.createElement("div");
marker.style.color = "#822";
marker.innerHTML = "●";
return marker;
};
toggleBreakpointLine = function(n) {
@ -77,9 +77,9 @@ getBreakpoints = function() {
if (line.gutterMarkers && line.gutterMarkers["breakpoints"]) {
var l = doc.getLineNumber(line);
locations.push({
start: editor.indexFromPos({ line: l, ch: 0}),
end: editor.indexFromPos({ line: l + 1, ch: 0})
});;
start: editor.indexFromPos({ line: l, ch: 0}),
end: editor.indexFromPos({ line: l + 1, ch: 0})
});;
}
});
return locations;
@ -116,7 +116,7 @@ setMode = function(mode) {
else if (mode === "solidity")
{
CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, CodeMirror.hint.anyword);
CodeMirror.showHint(cm, CodeMirror.hint.anyword);
}
editor.setOption("extraKeys", {
"Ctrl-Space": "autocomplete"
@ -132,6 +132,8 @@ var executionMark;
highlightExecution = function(start, end) {
if (executionMark)
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" });
}
@ -145,3 +147,38 @@ isClean = function()
{
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.errorDetail = detail.replace(reg[0], "");
_return.line = reg[0].split(':')[1];
_return.column = reg[0].split(':')[2];
}
else
{
_return.errorLocation = "";
_return.errorDetail = detail;
_return.line = "";
_return.column = "";
}
_return.errorLine = raw.split('\n')[1];
return _return;
}

1
mix/web.qrc

@ -27,6 +27,7 @@
<file>qml/html/cm/closebrackets.js</file>
<file>qml/html/cm/solidityToken.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/ecma5spec.js</file>
<file>qml/html/cm/comment.js</file>

385
neth/main.cpp

@ -31,12 +31,15 @@
#include <libdevcrypto/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libethereum/All.h>
#include <libwebthree/WebThree.h>
#if ETH_JSONRPC
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#endif
#include <libwebthree/WebThree.h>
#include "BuildInfo.h"
#undef KEY_EVENT // from windows.h
@ -68,26 +71,37 @@ void help()
<< "Usage neth [OPTIONS]" << endl
<< "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -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
<< " -d,--db-path <path> Load database from path (default: ~/.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
#if ETH_JSONRPC
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
#endif
<< " -K,--kill-blockchain First kill the blockchain." << 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
<< " -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
<< " -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
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << 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);
}
@ -113,6 +127,10 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << 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
<< " exit Exits the application." << endl;
}
@ -319,7 +337,14 @@ int main(int argc, char** argv)
bool upnp = true;
bool useLocal = false;
bool forceMining = false;
bool killChain = false;
bool jit = false;
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string clientName;
TransactionPriority priority = TransactionPriority::Medium;
double etherPrice = 30.679;
double blockFees = 15.0;
// Init defaults
Defaults::get();
@ -367,6 +392,10 @@ int main(int argc, char** argv)
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)
clientName = argv[++i];
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)
us = KeyPair(h256(fromHex(argv[++i])));
else if (arg == "--structured-logging-format" && i + 1 < argc)
structuredLoggingFormat = string(argv[++i]);
else if (arg == "--structured-logging")
structuredLogging = true;
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i];
else if ((arg == "-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)
{
string m = argv[++i];
@ -423,6 +502,28 @@ int main(int argc, char** argv)
peers = atoi(argv[++i]);
else if ((arg == "-t" || arg == "--miners") && i + 1 < argc)
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")
help();
else if (arg == "-V" || arg == "--version")
@ -438,35 +539,41 @@ int main(int argc, char** argv)
clientName += "/";
cout << credits();
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3(
"NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM),
clientImplString,
dbPath,
false,
killChain,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs,
&nodesState,
miners
);
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;
StructuredLogger::starting(clientImplString, dev::Version);
if (c)
{
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
c->setAddress(coinbase);
}
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
cout << "Transaction Signer: " << us.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl;
web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
if (mining)
if (c && mining)
c->startMining();
#if ETH_JSONRPC
@ -474,7 +581,7 @@ int main(int argc, char** argv)
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1)
{
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc));
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
@ -608,6 +715,42 @@ int main(int argc, char** argv)
iss >> 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")
{
if (iss.peek() != -1)
@ -625,7 +768,11 @@ int main(int argc, char** argv)
{
if (jsonrpc < 0)
jsonrpc = 8080;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc));
#if ETH_DEBUG
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->setIdentities({us});
jsonrpcServer->StartListening();
@ -647,7 +794,7 @@ int main(int argc, char** argv)
ccout << "Current secret:" << endl;
ccout << toHex(us.secret().asArray()) << endl;
}
else if (cmd == "block")
else if (c && cmd == "block")
{
unsigned n = c->blockChain().details().number;
ccout << "Current block # ";
@ -660,13 +807,13 @@ int main(int argc, char** argv)
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
<< endl;
}
else if (cmd == "balance")
else if (c && cmd == "balance")
{
u256 balance = c->balanceAt(us.address());
ccout << "Current balance:" << endl;
ccout << toString(balance) << endl;
}
else if (cmd == "transact")
else if (c && cmd == "transact")
{
auto const& bc = c->blockChain();
auto h = bc.currentHash();
@ -708,6 +855,8 @@ int main(int argc, char** argv)
stringstream ssp;
ssp << fields[2];
ssp >> gasPrice;
if (!gasPrice)
gasPrice = gasPricer->bid(priority);
string sechex = fields[4];
string sdata = fields[5];
cnote << "Data:";
@ -753,7 +902,7 @@ int main(int argc, char** argv)
}
}
}
else if (cmd == "send")
else if (c && cmd == "send")
{
vector<string> s;
s.push_back("Address");
@ -804,7 +953,7 @@ int main(int argc, char** argv)
}
}
}
else if (cmd == "contract")
else if (c && cmd == "contract")
{
auto const& bc = c->blockChain();
auto h = bc.currentHash();
@ -887,7 +1036,7 @@ int main(int argc, char** argv)
}
}
}
else if (cmd == "inspect")
else if (c && cmd == "inspect")
{
string rechex;
iss >> rechex;
@ -933,111 +1082,119 @@ int main(int argc, char** argv)
interactiveHelp();
else if (cmd == "exit")
break;
else if (cmd != "")
cwarn << "Unrecognised command. Type 'help' for a list of available commands.";
// Clear cmd at each pass
cmd = "";
// Lock to prevent corrupt block-chain errors
auto const& bc = c->blockChain();
ccout << "Genesis hash: " << bc.genesisHash() << endl;
// Contracts and addresses count / offset
int cc = 1;
int ca = 0;
// Blocks
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);
if (c) {
// Lock to prevent corrupt block-chain errors
auto const& bc = c->blockChain();
ccout << "Genesis hash: " << bc.genesisHash() << endl;
auto b = bc.block(h);
for (auto const& i: RLP(b)[1])
// Blocks
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() ?
boost::format(" %1% %2%> %3%: %4% [%5%]") %
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%]") %
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)
mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth);
if (y > height * 1 / 5 - 2)
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
y = 1;
int cc = 1;
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())
// Peers
y = 1;
for (PeerSessionInfo const& i: web3.peers())
{
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)
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;
}
// 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);
@ -1050,31 +1207,41 @@ int main(int argc, char** argv)
// Balance
stringstream ssb;
u256 balance = c->balanceAt(us.address());
ssb << "Balance: " << formatBalance(balance);
u256 balance;
if (c)
balance = c->balanceAt(us.address());
ssb << "Balance: ";
if (c)
ssb << formatBalance(balance);
mvwprintw(consolewin, 0, x, ssb.str().c_str());
// Block
mvwprintw(blockswin, 0, x, "Block # ");
unsigned n = c->blockChain().details().number;
mvwprintw(blockswin, 0, 10, toString(n).c_str());
if (c) {
unsigned n = c->blockChain().details().number;
mvwprintw(blockswin, 0, 10, toString(n).c_str());
}
// Pending
string pc;
pc = "Pending: " + toString(c->pending().size());
mvwprintw(pendingwin, 0, x, pc.c_str());
stringstream pc;
pc << "Pending: ";
if (c)
pc << toString(c->pending().size());
else
pc << 0;
mvwprintw(pendingwin, 0, x, pc.str().c_str());
// Contracts
string sc = "Contracts: ";
sc += toString(cc - 1);
mvwprintw(contractswin, 0, x, sc.c_str());
stringstream sc;
sc << "Contracts: " << cc - 1;
mvwprintw(contractswin, 0, x, sc.str().c_str());
// Peers
mvwprintw(peerswin, 0, x, "Peers: ");
mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str());
// Mining flag
if (c->isMining())
if (c && c->isMining())
{
mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON");
dev::eth::MineProgress p = c->miningProgress();
@ -1087,9 +1254,9 @@ int main(int argc, char** argv)
wmove(consolewin, 1, x);
// Addresses
string ac;
ac = "Addresses: " + toString(acs.size());
mvwprintw(addswin, 0, x, ac.c_str());
stringstream ac;
ac << "Addresses: " << ca;
mvwprintw(addswin, 0, x, ac.str().c_str());
wrefresh(consolewin);

7
test/transaction.cpp

@ -48,6 +48,13 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
if (!txFromRlp.signature().isValid())
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
}
catch(Exception const& _e)
{
cnote << i.first;
cnote << "Transaction Exception: " << diagnostic_information(_e);
BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!");
continue;
}
catch(...)
{
BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!");

15
test/ttTransactionTestFiller.json

@ -571,6 +571,7 @@
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
}
},
"unpadedRValue": {
"transaction": {
"nonce": "13",
@ -583,5 +584,19 @@
"v": "28",
"value": ""
}
},
"libsecp256k1test": {
"transaction": {
"nonce": "",
"gasPrice": "0x09184e72a000",
"gasLimit": "0x1388",
"to": "",
"data": "",
"r": "44",
"s": "4",
"v": "27",
"value": ""
}
}
}

Loading…
Cancel
Save