yann300
10 years ago
62 changed files with 2556 additions and 1010 deletions
@ -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) |
|||
|
@ -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; |
|||
} |
@ -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}[.].*") |
|||
|
@ -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 ) |
|||
|
@ -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)); |
|||
} |
@ -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; |
|||
}; |
|||
|
@ -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; |
|||
} |
@ -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(); |
|||
} |
@ -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.
|
|||
|
|||
}; |
|||
|
|||
}} |
@ -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); |
|||
} |
@ -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; |
|||
}; |
|||
|
|||
} |
|||
} |
@ -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} ) |
|||
|
@ -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(); |
|||
} |
|||
|
@ -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(); |
|||
|
|||
} |
|||
|
|||
} |
@ -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); |
|||
} |
@ -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.
|
|||
}; |
|||
|
|||
} |
|||
} |
@ -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" |
@ -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; |
|||
}; |
@ -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(); |
|||
} |
@ -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; |
|||
}; |
|||
} |
|||
} |
@ -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); |
|||
} |
@ -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; |
|||
}; |
|||
|
|||
} |
|||
} |
@ -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(); |
|||
} |
Loading…
Reference in new issue