Browse Source

Merge branch 'develop' into discovery

cl-refactor
subtly 10 years ago
parent
commit
68e6496f17
  1. 13
      CMakeLists.txt
  2. 2
      alethzero/Debugger.h
  3. 12
      alethzero/ExportState.cpp
  4. 2
      alethzero/MainWin.cpp
  5. 1
      cmake/EthCompilerSettings.cmake
  6. 10
      cmake/EthDependencies.cmake
  7. 49
      cmake/Findv8.cmake
  8. 8
      eth/CMakeLists.txt
  9. 42
      eth/main.cpp
  10. 308
      exp/main.cpp
  11. 2
      libdevcore/Common.cpp
  12. 17
      libdevcore/Common.h
  13. 8
      libdevcore/CommonData.h
  14. 17
      libdevcore/FixedHash.cpp
  15. 28
      libdevcore/FixedHash.h
  16. 24
      libdevcore/Log.h
  17. 1
      libdevcore/RLP.h
  18. 2
      libdevcrypto/Common.cpp
  19. 4
      libdevcrypto/Common.h
  20. 8
      libdevcrypto/MemoryDB.cpp
  21. 10
      libdevcrypto/MemoryDB.h
  22. 220
      libdevcrypto/SecretStore.cpp
  23. 56
      libdevcrypto/SecretStore.h
  24. 13
      libdevcrypto/TrieDB.h
  25. 16
      libethcore/BlockInfo.cpp
  26. 6
      libethcore/EthashAux.h
  27. 6
      libethereum/Account.h
  28. 2
      libethereum/AccountDiff.h
  29. 4
      libethereum/BlockChain.cpp
  30. 4
      libethereum/BlockChain.h
  31. 18
      libethereum/BlockQueue.h
  32. 4
      libethereum/CachedAddressState.cpp
  33. 2
      libethereum/CachedAddressState.h
  34. 4
      libethereum/CanonBlockChain.cpp
  35. 2
      libethereum/CanonBlockChain.h
  36. 12
      libethereum/Client.cpp
  37. 7
      libethereum/Client.h
  38. 22
      libethereum/ClientBase.cpp
  39. 16
      libethereum/ClientBase.h
  40. 4
      libethereum/DownloadMan.cpp
  41. 12
      libethereum/DownloadMan.h
  42. 3
      libethereum/EthereumHost.cpp
  43. 10
      libethereum/EthereumHost.h
  44. 5
      libethereum/EthereumPeer.h
  45. 4
      libethereum/ExtVM.h
  46. 16
      libethereum/Interface.h
  47. 203
      libethereum/KeyManager.cpp
  48. 110
      libethereum/KeyManager.h
  49. 4
      libethereum/LogFilter.h
  50. 4
      libethereum/Precompiled.cpp
  51. 4
      libethereum/Precompiled.h
  52. 23
      libethereum/State.cpp
  53. 17
      libethereum/State.h
  54. 6
      libethereum/Transaction.h
  55. 18
      libethereum/TransactionQueue.h
  56. 1
      libethereum/TransactionReceipt.h
  57. 2
      libethereumx/Ethereum.cpp
  58. 2
      libethereumx/Ethereum.h
  59. 30
      libjsconsole/CMakeLists.txt
  60. 86
      libjsconsole/JSConsole.cpp
  61. 53
      libjsconsole/JSConsole.h
  62. 54
      libjsconsole/JSV8Connector.cpp
  63. 50
      libjsconsole/JSV8Connector.h
  64. 36
      libjsengine/CMakeLists.txt
  65. 11
      libjsengine/Common.js
  66. 36
      libjsengine/JSEngine.cpp
  67. 60
      libjsengine/JSEngine.h
  68. 23
      libjsengine/JSPrinter.cpp
  69. 41
      libjsengine/JSPrinter.h
  70. 8
      libjsengine/JSResources.cmake
  71. 187
      libjsengine/JSV8Engine.cpp
  72. 61
      libjsengine/JSV8Engine.h
  73. 49
      libjsengine/JSV8Printer.cpp
  74. 43
      libjsengine/JSV8Printer.h
  75. 84
      libjsengine/JSV8RPC.cpp
  76. 47
      libjsengine/JSV8RPC.h
  77. 91
      libjsengine/PrettyPrint.js
  78. 23
      libp2p/Common.h
  79. 4
      libp2p/Host.h
  80. 2
      libp2p/Network.cpp
  81. 36
      libp2p/NodeTable.h
  82. 2
      libsolidity/ASTPrinter.h
  83. 66
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  84. 7
      libweb3jsonrpc/WebThreeStubServerBase.h
  85. 6
      mix/ClientModel.cpp
  86. 4
      mix/ClientModel.h
  87. 2
      mix/MachineStates.h
  88. 52
      mix/MixClient.cpp
  89. 12
      mix/MixClient.h
  90. 17
      test/CMakeLists.txt
  91. 2
      test/TestHelper.cpp
  92. 2
      test/fuzzTesting/checkRandomStateTest.cpp
  93. 1596
      test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json
  94. 323
      test/libethereum/blockchain.cpp
  95. 2
      test/libethereum/state.cpp
  96. 5
      test/libjsengine/CMakeLists.txt
  97. 71
      test/libjsengine/JSV8Engine.cpp

13
CMakeLists.txt

@ -40,6 +40,7 @@ option(GUI "Build GUI components (AlethZero, Mix)" ON)
option(TESTS "Build the tests." ON)
option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF)
option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF)
option(JSCONSOLE "Build in javascript console" OFF)
# propagates CMake configuration options to the compiler
function(configureProject)
@ -193,9 +194,14 @@ eth_format_option(GUI)
eth_format_option(TESTS)
eth_format_option(TOOLS)
eth_format_option(ETHASHCL)
eth_format_option(JSCONSOLE)
eth_format_option_on_decent_platform(SERPENT)
eth_format_option_on_decent_platform(NCURSES)
if (JSCONSOLE)
set(JSONRPC ON)
endif()
if (GUI)
set(JSONRPC ON)
endif()
@ -284,6 +290,7 @@ message("-- GUI Build GUI components ${GUI}")
message("-- NCURSES Build NCurses components ${NCURSES}")
message("-- TESTS Build tests ${TESTS}")
message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}")
message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}")
message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}")
message("------------------------------------------------------------------------")
message("")
@ -328,6 +335,11 @@ if (JSONRPC)
add_subdirectory(libweb3jsonrpc)
endif()
if (JSCONSOLE)
add_subdirectory(libjsengine)
add_subdirectory(libjsconsole)
endif()
add_subdirectory(secp256k1)
add_subdirectory(libp2p)
add_subdirectory(libdevcrypto)
@ -384,6 +396,7 @@ if (GUI)
endif()
#unset(TARGET_PLATFORM CACHE)
if (WIN32)

2
alethzero/Debugger.h

@ -45,7 +45,7 @@ struct WorldState
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::unordered_map<dev::u256, dev::u256> storage;
std::vector<WorldState const*> levels;
};

12
alethzero/ExportState.cpp

@ -91,7 +91,7 @@ void ExportStateDialog::fillBlocks()
while (i > 0 && i >= m_recentBlocks)
ui->block->removeItem(i--);
h256Set blocks;
h256Hash blocks;
for (QString f: filters)
{
if (f.startsWith("#"))
@ -153,13 +153,17 @@ void ExportStateDialog::generateJSON()
auto address = Address((byte const*)hba.data(), Address::ConstructFromPointer);
json << prefix << "\t\"" << toHex(address.ref()) << "\":\n\t{\n\t\t\"wei\": \"" << ethereum()->balanceAt(address, m_block) << "\",\n";
json << "\t\t\"code\": \"" << toHex(ethereum()->codeAt(address, m_block)) << "\",\n";
std::map<u256, u256> storage = ethereum()->storageAt(address, m_block);
std::unordered_map<u256, u256> storage = ethereum()->storageAt(address, m_block);
if (!storage.empty())
{
json << "\t\t\"storage\":\n\t\t{\n";
std::string storagePrefix;
for (auto s: storage)
json << "\t\t\t\"" << toHex(s.first) << "\": \"" << toHex(s.second) << "\"" << (s.first == storage.rbegin()->first ? "" : ",") <<"\n";
json << "\t\t}\n";
{
json << storagePrefix << "\t\t\t\"" << toHex(s.first) << "\": \"" << toHex(s.second) << "\"";
storagePrefix = ",\n";
}
json << "\n\t\t}\n";
}
json << "\t}";
prefix = ",\n";

2
alethzero/MainWin.cpp

@ -1092,7 +1092,7 @@ void Main::refreshBlockChain()
auto const& bc = ethereum()->blockChain();
QStringList filters = ui->blockChainFilter->text().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
h256Set blocks;
h256Hash blocks;
for (QString f: filters)
if (f.size() == 64)
{

1
cmake/EthCompilerSettings.cmake

@ -55,6 +55,7 @@ endif ()
if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")))
set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")
set(CMAKE_C_FLAGS "-g ${CMAKE_C_FLAGS}")
add_definitions(-DETH_PROFILING_GPERF)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lprofiler")
# set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -lprofiler")

10
cmake/EthDependencies.cmake

@ -31,7 +31,8 @@ endif()
# homebrew installs qts in opt
if (APPLE)
set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/qt5")
set (CMAKE_PREFIX_PATH "/usr/local/opt/qt5" ${CMAKE_PREFIX_PATH})
set (CMAKE_PREFIX_PATH "/usr/local/opt/v8-315" ${CMAKE_PREFIX_PATH})
endif()
find_program(CTEST_COMMAND ctest)
@ -47,6 +48,13 @@ find_package (LevelDB REQUIRED)
message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}")
message(" - LevelDB lib: ${LEVELDB_LIBRARIES}")
if (JSCONSOLE)
find_package (v8 REQUIRED)
message(" - v8 header: ${V8_INCLUDE_DIRS}")
message(" - v8 lib : ${V8_LIBRARIES}")
add_definitions(-DETH_JSCONSOLE)
endif()
# TODO the Jsoncpp package does not yet check for correct version number
find_package (Jsoncpp 0.60 REQUIRED)
message(" - Jsoncpp header: ${JSONCPP_INCLUDE_DIRS}")

49
cmake/Findv8.cmake

@ -0,0 +1,49 @@
# Find v8
#
# Find the v8 includes and library
#
# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH
#
# This module defines
# V8_INCLUDE_DIRS, where to find header, etc.
# V8_LIBRARIES, the libraries needed to use v8.
# V8_FOUND, If false, do not try to use v8.
# only look in default directories
find_path(
V8_INCLUDE_DIR
NAMES v8.h
DOC "v8 include dir"
)
find_library(
V8_LIBRARY
NAMES v8
DOC "v8 library"
)
set(V8_INCLUDE_DIRS ${V8_INCLUDE_DIR})
set(V8_LIBRARIES ${V8_LIBRARY})
# debug library on windows
# same naming convention as in qt (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug"
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
V8_LIBRARY_DEBUG
NAMES v8d
DOC "v8 debug library"
)
set(V8_LIBRARIES optimized ${V8_LIBRARIES} debug ${V8_LIBRARY_DEBUG})
endif()
# handle the QUIETLY and REQUIRED arguments and set V8_FOUND to TRUE
# if all listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(v8 DEFAULT_MSG
V8_INCLUDE_DIR V8_LIBRARY)
mark_as_advanced (V8_INCLUDE_DIR V8_LIBRARY)

8
eth/CMakeLists.txt

@ -7,6 +7,10 @@ include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
if (JSCONSOLE)
include_directories(${V8_INCLUDE_DIRS})
endif()
set(EXECUTABLE eth)
file(GLOB HEADERS "*.h")
@ -33,6 +37,10 @@ endif()
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethash)
if (JSCONSOLE)
target_link_libraries(${EXECUTABLE} jsconsole)
endif()
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()

42
eth/main.cpp

@ -38,6 +38,9 @@
#include <libevm/VMFactory.h>
#include <libethereum/All.h>
#include <libwebthree/WebThree.h>
#if ETH_JSCONSOLE || !ETH_TRUE
#include <libjsconsole/JSConsole.h>
#endif
#if ETH_READLINE || !ETH_TRUE
#include <readline/readline.h>
#include <readline/history.h>
@ -124,6 +127,7 @@ void help()
<< " -R,--rebuild Rebuild the blockchain from the existing database." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -S,--session-secret <secretkeyhex> Set the secret key for use with send command, for this session only." << endl
<< " --master <password> Give the master password for the key store." << endl
<< "Client transacting:" << endl
<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl
<< " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (default: 30.679)." << endl
@ -179,6 +183,9 @@ void help()
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl
<< " -h,--help Show this help message and exit." << endl
#if ETH_JSCONSOLE || !ETH_TRUE
<< " --console Use interactive javascript console" << endl
#endif
;
exit(0);
}
@ -406,6 +413,13 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
exit(0);
}
void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned _mining)
{
if (_c->isMining() && _c->blockChain().details().number - _start == _mining)
_c->stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
}
int main(int argc, char** argv)
{
#if 0
@ -542,10 +556,16 @@ int main(int argc, char** argv)
unsigned benchmarkTrial = 3;
unsigned benchmarkTrials = 5;
// javascript console
bool useConsole = false;
/// Farm params
string farmURL = "http://127.0.0.1:8080";
unsigned farmRecheckPeriod = 500;
/// Wallet password stuff
string masterPassword;
string configFile = getDataDir() + "/config.rlp";
bytes b = contents(configFile);
if (b.size())
@ -580,6 +600,8 @@ int main(int argc, char** argv)
cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl;
remotePort = (short)atoi(argv[++i]);
}
else if (arg == "--master" && i + 1 < argc)
masterPassword = argv[++i];
else if ((arg == "-I" || arg == "--import") && i + 1 < argc)
{
mode = OperationMode::Import;
@ -888,6 +910,10 @@ int main(int argc, char** argv)
jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc)
jsonrpc = atoi(argv[++i]);
#endif
#if ETH_JSCONSOLE
else if (arg == "--console")
useConsole = true;
#endif
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
g_logVerbosity = atoi(argv[++i]);
@ -1625,12 +1651,20 @@ int main(int argc, char** argv)
unsigned n =c->blockChain().details().number;
if (mining)
c->startMining();
while (!g_exit)
if (useConsole)
{
if ( c->isMining() &&c->blockChain().details().number - n == mining)
c->stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
#if ETH_JSCONSOLE
JSConsole console(web3, vector<KeyPair>({sigKey}));
while (!g_exit)
{
console.repl();
stopMiningAfterXBlocks(c, n, mining);
}
#endif
}
else
while (!g_exit)
stopMiningAfterXBlocks(c, n, mining);
}
else
while (!g_exit)

308
exp/main.cpp

@ -42,10 +42,12 @@
#include <libdevcore/TransientDirectory.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h>
#include <libethcore/ProofOfWork.h>
#include <libdevcrypto/FileSystem.h>
#include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libethereum/Farm.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
@ -64,304 +66,26 @@ namespace fs = boost::filesystem;
#if 1
inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); }
inline std::string toUUID(h128 const& _uuid) { std::string ret = toHex(_uuid.ref()); for (unsigned i: {20, 16, 12, 8}) ret.insert(ret.begin() + i, '-'); return ret; }
class KeyStore
{
public:
KeyStore() { readKeys(); }
~KeyStore() {}
bytes key(h128 const& _uuid, function<std::string()> const& _pass)
{
auto rit = m_cached.find(_uuid);
if (rit != m_cached.end())
return rit->second;
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
return bytes();
bytes key = decrypt(it->second, _pass());
if (!key.empty())
m_cached[_uuid] = key;
return key;
}
h128 import(bytes const& _s, std::string const& _pass)
{
h128 r = h128::random();
m_cached[r] = _s;
m_keys[r] = encrypt(_s, _pass);
writeKeys();
return r;
}
// Clear any cached keys.
void clearCache() const { m_cached.clear(); }
private:
void writeKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
fs::path p(_keysPath);
boost::filesystem::create_directories(p);
for (auto const& k: m_keys)
{
std::string uuid = toUUID(k.first);
js::mObject v;
v["crypto"] = k.second;
v["id"] = uuid;
v["version"] = 2;
writeFile((p / uuid).string() + ".json", js::write_string(js::mValue(v), true));
}
}
void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys")
{
fs::path p(_keysPath);
js::mValue v;
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path()))
{
cdebug << "Reading" << it->path();
js::read_string(contentsString(it->path().string()), v);
if (v.type() == js::obj_type)
{
js::mObject o = v.get_obj();
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0;
if (version == 2)
m_keys[fromUUID(o["id"].get_str())] = o["crypto"];
else
cwarn << "Cannot read key version" << version;
}
// else
// cwarn << "Invalid JSON in key file" << it->path().string();
}
}
static js::mValue encrypt(bytes const& _v, std::string const& _pass)
{
js::mObject ret;
// KDF info
unsigned dklen = 16;
unsigned iterations = 262144;
bytes salt = h256::random().asBytes();
ret["kdf"] = "pbkdf2";
{
js::mObject params;
params["prf"] = "hmac-sha256";
params["c"] = (int)iterations;
params["salt"] = toHex(salt);
params["dklen"] = (int)dklen;
ret["kdfparams"] = params;
}
bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen);
// cipher info
ret["cipher"] = "aes-128-cbc";
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv = h128::random();
{
js::mObject params;
params["iv"] = toHex(iv.ref());
ret["cipherparams"] = params;
}
// cipher text
bytes cipherText = encryptSymNoAuth(key, iv, &_v);
ret["ciphertext"] = toHex(cipherText);
// and mac.
h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
ret["mac"] = toHex(mac.ref());
return ret;
}
static bytes decrypt(js::mValue const& _v, std::string const& _pass)
{
js::mObject o = _v.get_obj();
// derive key
bytes derivedKey;
if (o["kdf"].get_str() == "pbkdf2")
{
auto params = o["kdfparams"].get_obj();
if (params["prf"].get_str() != "hmac-sha256")
{
cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported.";
return bytes();
}
unsigned iterations = params["c"].get_int();
bytes salt = fromHex(params["salt"].get_str());
derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int());
}
else
{
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes();
}
bytes cipherText = fromHex(o["ciphertext"].get_str());
// check MAC
h256 mac(o["mac"].get_str());
h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
// decrypt
if (o["cipher"].get_str() == "aes-128-cbc")
{
auto params = o["cipherparams"].get_obj();
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv(params["iv"].get_str());
return decryptSymNoAuth(key, iv, &cipherText);
}
else
{
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
return bytes();
}
}
mutable std::map<h128, bytes> m_cached;
std::map<h128, js::mValue> m_keys;
};
class UnknownPassword: public Exception {};
struct KeyInfo
{
h256 passHash;
std::string name;
};
static const auto DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(UnknownPassword()); return std::string(); };
// This one is specifically for Ethereum, but we can make it generic in due course.
// TODO: hidden-partition style key-store.
class KeyManager
int main()
{
public:
KeyManager() { m_cachedPasswords[sha3(m_password)] = m_password; }
~KeyManager() {}
void load(std::string const& _pass, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info")
{
try {
bytes salt = contents(_keysFile + ".salt");
bytes encKeys = contents(_keysFile);
m_key = h128(pbkdf2(_pass, salt, 262144, 16));
bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys);
RLP s(bs);
unsigned version = (unsigned)s[0];
if (version == 1)
{
for (auto const& i: s[1])
m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo{(h256)i[2], (std::string)i[3]};
for (auto const& i: s[2])
m_passwordInfo[(h256)i[0]] = (std::string)i[1];
m_password = (string)s[3];
}
}
catch (...) {}
m_cachedPasswords[sha3(m_password)] = m_password;
}
// Only use if previously loaded ok.
// @returns false if wasn't previously loaded ok.
bool save(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info") { if (!m_key) return false; save(m_key, _keysFile); return true; }
void save(std::string const& _pass, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info")
{
bytes salt = h256::random().asBytes();
writeFile(_keysFile + ".salt", salt);
auto key = h128(pbkdf2(_pass, salt, 262144, 16));
save(key, _keysFile);
}
void save(h128 const& _key, std::string const& _keysFile = getDataDir("ethereum") + "/keys.info")
{
RLPStream s(4);
s << 1;
s.appendList(m_addrLookup.size());
for (auto const& i: m_addrLookup)
s.appendList(4) << i.first << i.second << m_keyInfo[i.second].passHash << m_keyInfo[i.second].name;
s.appendList(m_passwordInfo.size());
for (auto const& i: m_passwordInfo)
s.appendList(2) << i.first << i.second;
s.append(m_password);
writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()));
m_key = _key;
}
Secret secret(Address const& _address, function<std::string()> const& _pass = DontKnowThrow)
{
auto it = m_addrLookup.find(_address);
if (it == m_addrLookup.end())
return Secret();
return secret(it->second, _pass);
}
Secret secret(h128 const& _uuid, function<std::string()> const& _pass = DontKnowThrow)
{
return Secret(m_store.key(_uuid, [&](){
auto it = m_cachedPasswords.find(m_keyInfo[_uuid].passHash);
if (it == m_cachedPasswords.end())
{
std::string p = _pass();
m_cachedPasswords[sha3(p)] = p;
return p;
}
else
return it->second;
}));
}
h128 import(Secret const& _s, std::string const& _pass, string const& _info = std::string(), string const& _passInfo = std::string())
{
Address addr = KeyPair(_s).address();
auto passHash = sha3(_pass);
m_cachedPasswords[passHash] = _pass;
m_passwordInfo[passHash] = _passInfo;
auto uuid = m_store.import(_s.asBytes(), _pass);
m_keyInfo[uuid] = KeyInfo{passHash, _info};
m_addrLookup[addr] = uuid;
return uuid;
}
h128 import(Secret const& _s, std::string const& _info = std::string())
{
// cache password, remember the key, remember the address
return import(_s, m_password, _info, std::string());
}
KeyManager keyman;
if (keyman.exists())
keyman.load("foo");
else
keyman.create("foo");
private:
// Ethereum keys.
std::map<Address, h128> m_addrLookup;
std::map<h128, KeyInfo> m_keyInfo;
std::map<h256, std::string> m_passwordInfo;
Address a("9cab1cc4e8fe528267c6c3af664a1adbce810b5f");
// Passwords that we're storing.
std::map<h256, std::string> m_cachedPasswords;
// keyman.importExisting(fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0"), "{\"name\":\"Gavin Wood - Main identity\"}", "bar", "{\"hint\":\"Not foo.\"}");
// Address a2 = keyman.address(keyman.import(Secret::random(), "Key with no additional security."));
// cdebug << toString(a2);
Address a2("19c486071651b2650449ba3c6a807f316a73e8fe");
// The default password for keys in the keystore - protected by the master password.
std::string m_password = asString(h256::random().asBytes());
cdebug << keyman.keys();
KeyStore m_store;
h128 m_key;
};
cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; });
cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);
int main()
{
KeyManager keyman;
auto id = fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0");
cdebug << "Secret key for " << toUUID(id) << "is" << keyman.secret(id, [](){ return "bar"; });
}
#elif 0

2
libdevcore/Common.cpp

@ -28,7 +28,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.9.16";
char const* Version = "0.9.17";
void HasInvariants::checkInvariants() const
{

17
libdevcore/Common.h

@ -34,10 +34,13 @@
#endif
#include <map>
#include <unordered_map>
#include <vector>
#include <set>
#include <unordered_set>
#include <functional>
#include <boost/timer.hpp>
#include <boost/functional/hash.hpp>
#pragma warning(push)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
@ -84,6 +87,10 @@ using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>;
using HexMap = std::map<bytes, std::string>;
// Hash types.
using StringHashMap = std::unordered_map<std::string, std::string>;
using u256HashMap = std::unordered_map<u256, u256>;
// String types.
using strings = std::vector<std::string>;
@ -215,4 +222,14 @@ inline dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
return static_cast<dev::WithExisting>(max(static_cast<int>(_a), static_cast<int>(_b)));
}
template <> struct hash<dev::u256>
{
size_t operator()(dev::u256 const& _a) const
{
unsigned size = _a.backend().size();
auto limbs = _a.backend().limbs();
return boost::hash_range(limbs, limbs + size);
}
};
}

8
libdevcore/CommonData.h

@ -258,6 +258,14 @@ template <class T, class U> std::set<T>& operator+=(std::set<T>& _a, U const& _b
return _a;
}
/// Insert the contents of a container into an unordered_st
template <class T, class U> std::unordered_set<T>& operator+=(std::unordered_set<T>& _a, U const& _b)
{
for (auto const& i: _b)
_a.insert(i);
return _a;
}
/// Concatenate the contents of a container onto a vector
template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U const& _b)
{

17
libdevcore/FixedHash.cpp

@ -19,10 +19,25 @@
* @date 2014
*/
#include <ctime>
#include "FixedHash.h"
#include <ctime>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace dev;
std::random_device dev::s_fixedHashEngine;
h128 dev::fromUUID(std::string const& _uuid)
{
return h128(boost::replace_all_copy(_uuid, "-", ""));
}
std::string dev::toUUID(h128 const& _uuid)
{
std::string ret = toHex(_uuid.ref());
for (unsigned i: {20, 16, 12, 8})
ret.insert(ret.begin() + i, '-');
return ret;
}

28
libdevcore/FixedHash.h

@ -150,17 +150,10 @@ public:
/// @returns a random valued object.
static FixedHash random() { return random(s_fixedHashEngine); }
/// A generic std::hash compatible function object.
struct hash
{
/// Make a hash of the object's data.
size_t operator()(FixedHash const& value) const
{
size_t h = 0;
for (auto i: value.m_data)
h = (h << (5 - h)) + i;
return h;
}
size_t operator()(FixedHash const& _value) const { return boost::hash_range(_value.m_data.cbegin(), _value.m_data.cend()); }
};
template <unsigned P, unsigned M> inline FixedHash& shiftBloom(FixedHash<M> const& _h)
@ -221,12 +214,8 @@ template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) co
/// Fast std::hash compatible hash function object for h256.
template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
{
const uint64_t*data = (const uint64_t*)value.data();
uint64_t hash = data[0];
hash ^= data[1];
hash ^= data[2];
hash ^= data[3];
return (size_t)hash;
uint64_t const* data = reinterpret_cast<uint64_t const*>(value.data());
return boost::hash_range(data, data + 4);
}
/// Stream I/O for the FixedHash class.
@ -254,6 +243,8 @@ using h256s = std::vector<h256>;
using h160s = std::vector<h160>;
using h256Set = std::set<h256>;
using h160Set = std::set<h160>;
using h256Hash = std::unordered_set<h256>;
using h160Hash = std::unordered_set<h160>;
/// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes.
inline h160 right160(h256 const& _t)
@ -271,6 +262,10 @@ inline h160 left160(h256 const& _t)
return ret;
}
h128 fromUUID(std::string const& _uuid);
std::string toUUID(h128 const& _uuid);
inline std::string toString(h256s const& _bs)
{
std::ostringstream out;
@ -285,6 +280,9 @@ inline std::string toString(h256s const& _bs)
namespace std
{
/// Forward std::hash<dev::h256> to dev::h256::hash.
/// Forward std::hash<dev::FixedHash> to dev::FixedHash::hash.
template<> struct hash<dev::h64>: dev::h64::hash {};
template<> struct hash<dev::h160>: dev::h160::hash {};
template<> struct hash<dev::h256>: dev::h256::hash {};
template<> struct hash<dev::h512>: dev::h512::hash {};
}

24
libdevcore/Log.h

@ -164,6 +164,30 @@ public:
}
m_sstr << EthLime "}" EthReset;
}
template <class T> void append(std::unordered_set<T> const& _t)
{
m_sstr << EthYellow "{" EthReset;
int n = 0;
for (auto const& i: _t)
{
m_sstr << (n++ ? EthYellow ", " EthReset : "");
append(i);
}
m_sstr << EthYellow "}" EthReset;
}
template <class T, class U> void append(std::unordered_map<T, U> const& _t)
{
m_sstr << EthLime "{" EthReset;
int n = 0;
for (auto const& i: _t)
{
m_sstr << (n++ ? EthLime ", " EthReset : "");
append(i.first);
m_sstr << (n++ ? EthLime ": " EthReset : "");
append(i.second);
}
m_sstr << EthLime "}" EthReset;
}
template <class T, class U> void append(std::pair<T, U> const& _t)
{
m_sstr << EthPurple "(" EthReset;

1
libdevcore/RLP.h

@ -362,6 +362,7 @@ public:
template <class _T> RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T, size_t S> RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T> RLPStream& append(std::set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T> RLPStream& append(std::unordered_set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class T, class U> RLPStream& append(std::pair<T, U> const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; }
/// Appends a list.

2
libdevcrypto/Common.cpp

@ -20,6 +20,7 @@
* @date 2014
*/
#include "Common.h"
#include <random>
#include <chrono>
#include <thread>
@ -28,7 +29,6 @@
#include "SHA3.h"
#include "FileSystem.h"
#include "CryptoPP.h"
#include "Common.h"
using namespace std;
using namespace dev;
using namespace dev::crypto;

4
libdevcrypto/Common.h

@ -68,8 +68,8 @@ extern Address ZeroAddress;
/// A vector of Ethereum addresses.
using Addresses = h160s;
/// A set of Ethereum addresses.
using AddressSet = std::set<h160>;
/// A hash set of Ethereum addresses.
using AddressHash = std::unordered_set<h160>;
/// A vector of secrets.
using Secrets = h256s;

8
libdevcrypto/MemoryDB.cpp

@ -30,9 +30,9 @@ namespace dev
const char* DBChannel::name() { return "TDB"; }
const char* DBWarn::name() { return "TDB"; }
std::map<h256, std::string> MemoryDB::get() const
std::unordered_map<h256, std::string> MemoryDB::get() const
{
std::map<h256, std::string> ret;
std::unordered_map<h256, std::string> ret;
for (auto const& i: m_main)
if (!m_enforceRefs || i.second.second > 0)
ret.insert(make_pair(i.first, i.second.first));
@ -112,9 +112,9 @@ void MemoryDB::purge()
it = m_main.erase(it);
}
set<h256> MemoryDB::keys() const
h256Hash MemoryDB::keys() const
{
set<h256> ret;
h256Hash ret;
for (auto const& i: m_main)
if (i.second.second)
ret.insert(i.first);

10
libdevcrypto/MemoryDB.h

@ -21,7 +21,7 @@
#pragma once
#include <map>
#include <unordered_map>
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
#include <libdevcore/Log.h>
@ -45,7 +45,7 @@ public:
MemoryDB() {}
void clear() { m_main.clear(); } // WARNING !!!! didn't originally clear m_refCount!!!
std::map<h256, std::string> get() const;
std::unordered_map<h256, std::string> get() const;
std::string lookup(h256 const& _h) const;
bool exists(h256 const& _h) const;
@ -57,11 +57,11 @@ public:
void removeAux(h256 const& _h) { m_aux[_h].second = false; }
void insertAux(h256 const& _h, bytesConstRef _v) { m_aux[_h] = make_pair(_v.toBytes(), true); }
std::set<h256> keys() const;
h256Hash keys() const;
protected:
std::map<h256, std::pair<std::string, unsigned>> m_main;
std::map<h256, std::pair<bytes, bool>> m_aux;
std::unordered_map<h256, std::pair<std::string, unsigned>> m_main;
std::unordered_map<h256, std::pair<bytes, bool>> m_aux;
mutable bool m_enforceRefs = false;
};

220
libdevcrypto/SecretStore.cpp

@ -0,0 +1,220 @@
/*
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 SecretStore.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "SecretStore.h"
#include <thread>
#include <mutex>
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/Guards.h>
#include <test/JsonSpiritHeaders.h>
#include "SHA3.h"
#include "FileSystem.h"
using namespace std;
using namespace dev;
namespace js = json_spirit;
namespace fs = boost::filesystem;
SecretStore::SecretStore()
{
load();
}
SecretStore::~SecretStore()
{
}
bytes SecretStore::secret(h128 const& _uuid, function<std::string()> const& _pass) const
{
auto rit = m_cached.find(_uuid);
if (rit != m_cached.end())
return rit->second;
auto it = m_keys.find(_uuid);
if (it == m_keys.end())
return bytes();
bytes key = decrypt(it->second.first, _pass());
if (!key.empty())
m_cached[_uuid] = key;
return key;
}
h128 SecretStore::importSecret(bytes const& _s, std::string const& _pass)
{
h128 r = h128::random();
m_cached[r] = _s;
m_keys[r] = make_pair(encrypt(_s, _pass), std::string());
save();
return r;
}
void SecretStore::kill(h128 const& _uuid)
{
m_cached.erase(_uuid);
if (m_keys.count(_uuid))
{
boost::filesystem::remove(m_keys[_uuid].second);
m_keys.erase(_uuid);
}
}
void SecretStore::clearCache() const
{
m_cached.clear();
}
void SecretStore::save(std::string const& _keysPath)
{
fs::path p(_keysPath);
boost::filesystem::create_directories(p);
for (auto& k: m_keys)
{
std::string uuid = toUUID(k.first);
std::string filename = (p / uuid).string() + ".json";
js::mObject v;
js::mValue crypto;
js::read_string(k.second.first, crypto);
v["crypto"] = crypto;
v["id"] = uuid;
v["version"] = 2;
writeFile(filename, js::write_string(js::mValue(v), true));
if (!k.second.second.empty() && k.second.second != filename)
boost::filesystem::remove(k.second.second);
k.second.second = filename;
}
}
void SecretStore::load(std::string const& _keysPath)
{
fs::path p(_keysPath);
js::mValue v;
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path()))
{
cdebug << "Reading" << it->path();
js::read_string(contentsString(it->path().string()), v);
if (v.type() == js::obj_type)
{
js::mObject o = v.get_obj();
int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0;
if (version == 2)
m_keys[fromUUID(o["id"].get_str())] = make_pair(js::write_string(o["crypto"], false), it->path().string());
else
cwarn << "Cannot read key version" << version;
}
// else
// cwarn << "Invalid JSON in key file" << it->path().string();
}
}
std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass)
{
js::mObject ret;
// KDF info
unsigned dklen = 16;
unsigned iterations = 262144;
bytes salt = h256::random().asBytes();
ret["kdf"] = "pbkdf2";
{
js::mObject params;
params["prf"] = "hmac-sha256";
params["c"] = (int)iterations;
params["salt"] = toHex(salt);
params["dklen"] = (int)dklen;
ret["kdfparams"] = params;
}
bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen);
// cipher info
ret["cipher"] = "aes-128-cbc";
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv = h128::random();
{
js::mObject params;
params["iv"] = toHex(iv.ref());
ret["cipherparams"] = params;
}
// cipher text
bytes cipherText = encryptSymNoAuth(key, iv, &_v);
ret["ciphertext"] = toHex(cipherText);
// and mac.
h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
ret["mac"] = toHex(mac.ref());
return js::write_string((js::mValue)ret, true);
}
bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass)
{
js::mObject o;
{
js::mValue ov;
js::read_string(_v, ov);
o = ov.get_obj();
}
// derive key
bytes derivedKey;
if (o["kdf"].get_str() == "pbkdf2")
{
auto params = o["kdfparams"].get_obj();
if (params["prf"].get_str() != "hmac-sha256")
{
cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported.";
return bytes();
}
unsigned iterations = params["c"].get_int();
bytes salt = fromHex(params["salt"].get_str());
derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int());
}
else
{
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes();
}
bytes cipherText = fromHex(o["ciphertext"].get_str());
// check MAC
h256 mac(o["mac"].get_str());
h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
}
// decrypt
if (o["cipher"].get_str() == "aes-128-cbc")
{
auto params = o["cipherparams"].get_obj();
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
h128 iv(params["iv"].get_str());
return decryptSymNoAuth(key, iv, &cipherText);
}
else
{
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
return bytes();
}
}

56
libdevcrypto/SecretStore.h

@ -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 SecretStore.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <functional>
#include <mutex>
#include "Common.h"
#include "FileSystem.h"
namespace dev
{
class SecretStore
{
public:
SecretStore();
~SecretStore();
bytes secret(h128 const& _uuid, std::function<std::string()> const& _pass) const;
h128 importSecret(bytes const& _s, std::string const& _pass);
void kill(h128 const& _uuid);
// Clear any cached keys.
void clearCache() const;
private:
void save(std::string const& _keysPath = getDataDir("web3") + "/keys");
void load(std::string const& _keysPath = getDataDir("web3") + "/keys");
static std::string encrypt(bytes const& _v, std::string const& _pass);
static bytes decrypt(std::string const& _v, std::string const& _pass);
mutable std::map<h128, bytes> m_cached;
std::map<h128, std::pair<std::string, std::string>> m_keys;
};
}

13
libdevcrypto/TrieDB.h

@ -26,7 +26,6 @@
#include <leveldb/db.h>
#pragma warning(pop)
#include <map>
#include <memory>
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
@ -105,7 +104,7 @@ public:
void debugPrint() {}
void descendKey(h256 _k, std::set<h256>& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const
void descendKey(h256 _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const
{
_keyMask.erase(_k);
if (_k == m_root && _k == c_shaNull) // root allowed to be empty
@ -113,7 +112,7 @@ public:
descendList(RLP(node(_k)), _keyMask, _wasExt, _out, _indent); // if not, it must be a list
}
void descendEntry(RLP const& _r, std::set<h256>& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
void descendEntry(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
{
if (_r.isData() && _r.size() == 32)
descendKey(_r.toHash<h256>(), _keyMask, _wasExt, _out, _indent);
@ -123,7 +122,7 @@ public:
BOOST_THROW_EXCEPTION(InvalidTrie());
}
void descendList(RLP const& _r, std::set<h256>& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
void descendList(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const
{
if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out))
{
@ -144,9 +143,9 @@ public:
BOOST_THROW_EXCEPTION(InvalidTrie());
}
std::set<h256> leftOvers(std::ostream* _out = nullptr) const
h256Hash leftOvers(std::ostream* _out = nullptr) const
{
std::set<h256> k = m_db->keys();
h256Hash k = m_db->keys();
descendKey(m_root, k, false, _out);
return k;
}
@ -431,7 +430,7 @@ public:
void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(_key, _value); m_secure.insert(_key, _value); syncRoot(); }
void remove(bytesConstRef _key) { Super::remove(_key); m_secure.remove(_key); syncRoot(); }
std::set<h256> leftOvers(std::ostream* = nullptr) const { return std::set<h256>{}; }
h256Hash leftOvers(std::ostream* = nullptr) const { return h256Hash{}; }
bool check(bool) const { return m_secure.check(false) && Super::check(false); }
private:

16
libethcore/BlockInfo.cpp

@ -195,26 +195,18 @@ template <class T, class U> h256 trieRootOver(unsigned _itemCount, T const& _get
return t.root();
}
struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "" EthWhite ""; } static const int verbosity = 9; };
void BlockInfo::verifyInternals(bytesConstRef _block) const
{
RLP root(_block);
/*OverlayDB db;
GenericTrieDB<OverlayDB> t(&db);
t.init();
unsigned i = 0;
for (auto const& tr: root[1])
{
bytes k = rlp(i);
t.insert(&k, tr.data());
++i;
}
if (transactionsRoot != t.root())*/
auto txList = root[1];
auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); });
clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot);
if (transactionsRoot != expectedRoot)
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot));
clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data()));
if (sha3Uncles != sha3(root[2].data()))
BOOST_THROW_EXCEPTION(InvalidUnclesHash());
}

6
libethcore/EthashAux.h

@ -75,12 +75,12 @@ private:
static EthashAux* s_this;
RecursiveMutex x_this;
std::map<h256, std::shared_ptr<LightAllocation>> m_lights;
std::map<h256, std::weak_ptr<FullAllocation>> m_fulls;
std::unordered_map<h256, std::shared_ptr<LightAllocation>> m_lights;
std::unordered_map<h256, std::weak_ptr<FullAllocation>> m_fulls;
FullType m_lastUsedFull;
Mutex x_epochs;
std::map<h256, unsigned> m_epochs;
std::unordered_map<h256, unsigned> m_epochs;
h256s m_seedHashes;
};

6
libethereum/Account.h

@ -134,8 +134,8 @@ public:
/// which encodes the base-state of the account's storage (upon which the storage is overlaid).
h256 baseRoot() const { assert(m_storageRoot); return m_storageRoot; }
/// @returns the storage overlay as a simple map.
std::map<u256, u256> const& storageOverlay() const { return m_storageOverlay; }
/// @returns the storage overlay as a simple hash map.
std::unordered_map<u256, u256> const& storageOverlay() const { return m_storageOverlay; }
/// Set a key/value pair in the account's storage. This actually goes into the overlay, for committing
/// to the trie later.
@ -194,7 +194,7 @@ private:
h256 m_codeHash = EmptySHA3;
/// The map with is overlaid onto whatever storage is implied by the m_storageRoot in the trie.
std::map<u256, u256> m_storageOverlay;
std::unordered_map<u256, u256> m_storageOverlay;
/// The associated code for this account. The SHA3 of this should be equal to m_codeHash unless m_codeHash
/// equals c_contractConceptionCodeHash.

2
libethereum/AccountDiff.h

@ -62,7 +62,7 @@ struct AccountDiff
Diff<bool> exist; ///< The account's existance; was it created/deleted or not?
Diff<u256> balance; ///< The account's balance; did it alter?
Diff<u256> nonce; ///< The account's nonce; did it alter?
std::map<u256, Diff<u256>> storage; ///< The account's storage addresses; each has its own Diff.
std::unordered_map<u256, Diff<u256>> storage; ///< The account's storage addresses; each has its own Diff.
Diff<bytes> code; ///< The account's code; in general this should only have changed if exist also changed.
};

4
libethereum/BlockChain.cpp

@ -961,10 +961,10 @@ vector<unsigned> BlockChain::withBlockBloom(LogBloom const& _b, unsigned _earlie
return ret;
}
h256Set BlockChain::allUnclesFrom(h256 const& _parent) const
h256Hash BlockChain::allUnclesFrom(h256 const& _parent) const
{
// Get all uncles cited given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
h256Set ret;
h256Hash ret;
h256 p = _parent;
for (unsigned i = 0; i < 6 && p != m_genesisHash; ++i, p = details(p).parent)
{

4
libethereum/BlockChain.h

@ -72,7 +72,7 @@ struct BlockChainWarn: public LogChannel { static const char* name(); static con
struct BlockChainDebug: public LogChannel { static const char* name(); static const int verbosity = 0; };
// TODO: Move all this Genesis stuff into Genesis.h/.cpp
std::map<Address, Account> const& genesisState();
std::unordered_map<Address, Account> const& genesisState();
ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0);
@ -206,7 +206,7 @@ public:
/// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
/// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5
/// togther with all their quoted uncles.
h256Set allUnclesFrom(h256 const& _parent) const;
h256Hash allUnclesFrom(h256 const& _parent) const;
/// Run through database and verify all blocks by reevaluating.
/// Will call _progress with the progress in this operation first param done, second total.

18
libethereum/BlockQueue.h

@ -106,15 +106,15 @@ private:
bool invariants() const override;
mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_drainingSet; ///< All blocks being imported.
std::set<h256> m_readySet; ///< All blocks ready for chain-import.
std::vector<std::pair<h256, bytes>> m_ready; ///< List of blocks, in correct order, ready for chain-import.
std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
std::set<h256> m_knownBad; ///< Set of blocks that we know will never be valid.
std::multimap<unsigned, std::pair<h256, bytes>> m_future;///< Set of blocks that are not yet valid.
Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
mutable boost::shared_mutex m_lock; ///< General lock.
h256Hash m_drainingSet; ///< All blocks being imported.
h256Hash m_readySet; ///< All blocks ready for chain-import.
std::vector<std::pair<h256, bytes>> m_ready; ///< List of blocks, in correct order, ready for chain-import.
h256Hash m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::unordered_multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
h256Hash m_knownBad; ///< Set of blocks that we know will never be valid.
std::multimap<unsigned, std::pair<h256, bytes>> m_future; ///< Set of blocks that are not yet valid. Ordered by timestamp
Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast.
};
}

4
libethereum/CachedAddressState.cpp

@ -51,9 +51,9 @@ bytes CachedAddressState::code() const
return h == EmptySHA3 ? bytes() : asBytes(m_o->lookup(h));
}
std::map<u256, u256> CachedAddressState::storage() const
std::unordered_map<u256, u256> CachedAddressState::storage() const
{
std::map<u256, u256> ret;
std::unordered_map<u256, u256> ret;
if (m_r)
{
SecureTrieDB<h256, OverlayDB> memdb(const_cast<OverlayDB*>(m_o), m_r[2].toHash<h256>()); // promise we won't alter the overlay! :)

2
libethereum/CachedAddressState.h

@ -47,7 +47,7 @@ public:
bytes code() const;
// TODO: DEPRECATE.
std::map<u256, u256> storage() const;
std::unordered_map<u256, u256> storage() const;
AccountDiff diff(CachedAddressState const& _c);

4
libethereum/CanonBlockChain.cpp

@ -41,9 +41,9 @@ namespace js = json_spirit;
#define ETH_CATCH 1
std::map<Address, Account> const& dev::eth::genesisState()
std::unordered_map<Address, Account> const& dev::eth::genesisState()
{
static std::map<Address, Account> s_ret;
static std::unordered_map<Address, Account> s_ret;
if (s_ret.empty())
{

2
libethereum/CanonBlockChain.h

@ -45,7 +45,7 @@ namespace eth
{
// TODO: Move all this Genesis stuff into Genesis.h/.cpp
std::map<Address, Account> const& genesisState();
std::unordered_map<Address, Account> const& genesisState();
/**
* @brief Implements the blockchain database. All data this gives is disk-backed.

12
libethereum/Client.cpp

@ -308,7 +308,7 @@ void Client::killChain()
void Client::clearPending()
{
h256Set changeds;
h256Hash changeds;
DEV_WRITE_GUARDED(x_postMine)
{
if (!m_postMine.pending().size())
@ -345,7 +345,7 @@ static S& filtersStreamOut(S& _out, T const& _fs)
return _out;
}
void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash)
void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _transactionHash)
{
Guard l(x_filtersWatches);
for (pair<h256 const, InstalledFilter>& i: m_filters)
@ -363,7 +363,7 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& i
}
}
void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed)
void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed)
{
// TODO: more precise check on whether the txs match.
auto d = m_bc.info(_block);
@ -496,7 +496,7 @@ void Client::syncTransactionQueue()
// returns TransactionReceipts, once for each transaction.
cwork << "postSTATE <== TQ";
h256Set changeds;
h256Hash changeds;
TransactionReceipts newPendingReceipts;
DEV_TIMED(working) DEV_WRITE_GUARDED(x_working)
@ -552,7 +552,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
if (auto h = m_host.lock())
h->noteNewBlocks();
h256Set changeds;
h256Hash changeds;
for (auto const& h: _ir.first)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
@ -631,7 +631,7 @@ void Client::startMining()
onPostStateChanged();
}
void Client::noteChanged(h256Set const& _filters)
void Client::noteChanged(h256Hash const& _filters)
{
Guard l(x_filtersWatches);
if (_filters.size())

7
libethereum/Client.h

@ -228,15 +228,15 @@ protected:
/// Collate the changed filters for the bloom filter of the given pending transaction.
/// Insert any filters that are activated into @a o_changed.
void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _sha3);
void appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _sha3);
/// Collate the changed filters for the hash of the given block.
/// Insert any filters that are activated into @a o_changed.
void appendFromNewBlock(h256 const& _blockHash, h256Set& io_changed);
void appendFromNewBlock(h256 const& _blockHash, h256Hash& io_changed);
/// Record that the set of filters @a _filters have changed.
/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
void noteChanged(h256Set const& _filters);
void noteChanged(h256Hash const& _filters);
private:
/// Called when Worker is starting.
@ -309,7 +309,6 @@ private:
ActivityReport m_report;
// TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables)
std::condition_variable m_signalled;
Mutex x_signalled;
std::atomic<bool> m_syncTransactionQueue = {false};

22
libethereum/ClientBase.cpp

@ -75,17 +75,17 @@ Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes con
}
// TODO: remove try/catch, allow exceptions
ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff)
ExecutionResult ClientBase::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff)
{
ExecutionResult ret;
try
{
State temp = asOf(_blockNumber);
Address a = toAddress(_secret);
u256 n = temp.transactionsFrom(a);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
u256 n = temp.transactionsFrom(_from);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
temp.addBalance(a, (u256)(t.gas() * t.gasPrice() + t.value()));
temp.addBalance(_from, (u256)(t.gas() * t.gasPrice() + t.value()));
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
@ -95,19 +95,19 @@ ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, byt
return ret;
}
ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff)
ExecutionResult ClientBase::create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff)
{
ExecutionResult ret;
try
{
State temp = asOf(_blockNumber);
Address a = toAddress(_secret);
u256 n = temp.transactionsFrom(a);
u256 n = temp.transactionsFrom(_from);
// 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);
Transaction t(_value, _gasPrice, _gas, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
@ -147,7 +147,7 @@ h256 ClientBase::codeHashAt(Address _a, BlockNumber _block) const
return asOf(_block).codeHash(_a);
}
map<u256, u256> ClientBase::storageAt(Address _a, BlockNumber _block) const
unordered_map<u256, u256> ClientBase::storageAt(Address _a, BlockNumber _block) const
{
return asOf(_block).storage(_a);
}

16
libethereum/ClientBase.h

@ -83,11 +83,13 @@ public:
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, FudgeFactor _ff = FudgeFactor::Strict) override;
virtual ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override;
using Interface::call;
/// Makes the given create. Nothing is recorded into the state.
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override;
virtual ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override;
using Interface::create;
using Interface::balanceAt;
using Interface::countAt;
using Interface::stateAt;
@ -100,7 +102,7 @@ public:
virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override;
virtual bytes codeAt(Address _a, BlockNumber _block) const override;
virtual h256 codeHashAt(Address _a, BlockNumber _block) const override;
virtual std::map<u256, u256> storageAt(Address _a, BlockNumber _block) const override;
virtual std::unordered_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;
@ -172,9 +174,9 @@ protected:
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.
mutable Mutex x_filtersWatches; ///< Our lock.
std::unordered_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.
};
}}

4
libethereum/DownloadMan.cpp

@ -39,7 +39,7 @@ DownloadSub::~DownloadSub()
}
}
h256Set DownloadSub::nextFetch(unsigned _n)
h256Hash DownloadSub::nextFetch(unsigned _n)
{
Guard l(m_fetch);
@ -51,7 +51,7 @@ h256Set DownloadSub::nextFetch(unsigned _n)
m_remaining.clear();
if (!m_man || m_man->chainEmpty())
return h256Set();
return h256Hash();
m_asked = (~(m_man->taken() + m_attempted)).lowest(_n);
if (m_asked.empty())

12
libethereum/DownloadMan.h

@ -21,9 +21,9 @@
#pragma once
#include <map>
#include <vector>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
@ -46,7 +46,7 @@ public:
~DownloadSub();
/// Finished last fetch - grab the next bunch of block hashes to download.
h256Set nextFetch(unsigned _n);
h256Hash nextFetch(unsigned _n);
/// Note that we've received a particular block. @returns true if we had asked for it but haven't received it yet.
bool noteBlock(h256 _hash);
@ -71,8 +71,8 @@ private:
DownloadMan* m_man = nullptr;
mutable Mutex m_fetch;
h256Set m_remaining;
std::map<h256, unsigned> m_indices;
h256Hash m_remaining;
std::unordered_map<h256, unsigned> m_indices;
RangeMask<unsigned> m_asked;
RangeMask<unsigned> m_attempted;
};
@ -155,7 +155,7 @@ private:
RangeMask<unsigned> m_blocksGot;
mutable SharedMutex x_subs;
std::set<DownloadSub*> m_subs;
std::unordered_set<DownloadSub*> m_subs;
};
}

3
libethereum/EthereumHost.cpp

@ -21,7 +21,6 @@
#include "EthereumHost.h"
#include <set>
#include <chrono>
#include <thread>
#include <libdevcore/Common.h>
@ -184,7 +183,7 @@ void EthereumHost::doWork()
void EthereumHost::maintainTransactions()
{
// Send any new transactions.
map<std::shared_ptr<EthereumPeer>, h256s> peerTransactions;
unordered_map<std::shared_ptr<EthereumPeer>, h256s> peerTransactions;
auto ts = m_tq.transactions();
for (auto const& i: ts)
{

10
libethereum/EthereumHost.h

@ -22,9 +22,9 @@
#pragma once
#include <mutex>
#include <map>
#include <unordered_map>
#include <vector>
#include <set>
#include <unordered_set>
#include <memory>
#include <utility>
#include <thread>
@ -97,7 +97,7 @@ private:
/// Get a bunch of needed blocks.
/// Removes them from our list of needed blocks.
/// @returns empty if there's no more blocks left to fetch, otherwise the blocks to fetch.
h256Set neededBlocks(h256Set const& _exclude);
h256Hash neededBlocks(h256Hash const& _exclude);
/// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return (bool)m_latestBlockSent; }
@ -121,9 +121,9 @@ private:
DownloadMan m_man;
h256 m_latestBlockSent;
h256Set m_transactionsSent;
h256Hash m_transactionsSent;
std::set<p2p::NodeId> m_banned;
std::unordered_set<p2p::NodeId> m_banned;
bool m_newTransactions = false;
bool m_newBlocks = false;

5
libethereum/EthereumPeer.h

@ -23,7 +23,6 @@
#include <mutex>
#include <array>
#include <set>
#include <memory>
#include <utility>
@ -140,9 +139,9 @@ private:
bool m_requireTransactions = false;
Mutex x_knownBlocks;
h256Set m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them).
h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them).
Mutex x_knownTransactions;
h256Set m_knownTransactions; ///< Transactions that the peer already knows of.
h256Hash m_knownTransactions; ///< Transactions that the peer already knows of.
};

4
libethereum/ExtVM.h

@ -91,8 +91,8 @@ public:
State& state() const { return m_s; }
private:
State& m_s; ///< A reference to the base state.
std::map<Address, Account> m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.
State& m_s; ///< A reference to the base state.
std::unordered_map<Address, Account> m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.
};
}

16
libethereum/Interface.h

@ -76,13 +76,17 @@ public:
virtual void flushTransactions() = 0;
/// Makes the given call. Nothing is recorded into the state.
virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0;
ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return call(_secret, _value, _dest, _data, _gas, _gasPrice, m_default, _ff); }
virtual ExecutionResult call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0;
ExecutionResult call(Address const& _from, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return call(_from, _value, _dest, _data, _gas, _gasPrice, m_default, _ff); }
ExecutionResult call(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) { return call(toAddress(_secret), _value, _dest, _data, _gas, _gasPrice, _blockNumber, _ff); }
ExecutionResult call(Secret const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, FudgeFactor _ff = FudgeFactor::Strict) { return call(toAddress(_secret), _value, _dest, _data, _gas, _gasPrice, _ff); }
/// 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, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0;
ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return create(_secret, _value, _data, _gas, _gasPrice, m_default, _ff); }
virtual ExecutionResult create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0;
ExecutionResult create(Address const& _from, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return create(_from, _value, _data, _gas, _gasPrice, m_default, _ff); }
ExecutionResult create(Secret const& _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) { return create(toAddress(_secret), _value, _data, _gas, _gasPrice, _blockNumber, _ff); }
ExecutionResult create(Secret const& _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, FudgeFactor _ff = FudgeFactor::Strict) { return create(toAddress(_secret), _value, _data, _gas, _gasPrice, _ff); }
/// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly.
virtual ImportResult injectTransaction(bytes const& _rlp) = 0;
@ -100,14 +104,14 @@ public:
u256 stateAt(Address _a, u256 _l) const { return stateAt(_a, _l, m_default); }
bytes codeAt(Address _a) const { return codeAt(_a, m_default); }
h256 codeHashAt(Address _a) const { return codeHashAt(_a, m_default); }
std::map<u256, u256> storageAt(Address _a) const { return storageAt(_a, m_default); }
std::unordered_map<u256, u256> storageAt(Address _a) const { return storageAt(_a, m_default); }
virtual u256 balanceAt(Address _a, BlockNumber _block) const = 0;
virtual u256 countAt(Address _a, BlockNumber _block) const = 0;
virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const = 0;
virtual bytes codeAt(Address _a, BlockNumber _block) const = 0;
virtual h256 codeHashAt(Address _a, BlockNumber _block) const = 0;
virtual std::map<u256, u256> storageAt(Address _a, BlockNumber _block) const = 0;
virtual std::unordered_map<u256, u256> storageAt(Address _a, BlockNumber _block) const = 0;
// [LOGS API]

203
libethereum/KeyManager.cpp

@ -0,0 +1,203 @@
/*
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 KeyManager.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "KeyManager.h"
#include <thread>
#include <mutex>
#include <boost/filesystem.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/Guards.h>
#include <libdevcore/RLP.h>
using namespace std;
using namespace dev;
namespace fs = boost::filesystem;
KeyManager::KeyManager(std::string const& _keysFile):
m_keysFile(_keysFile)
{}
KeyManager::~KeyManager()
{}
bool KeyManager::exists() const
{
return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty();
}
void KeyManager::create(std::string const& _pass)
{
m_password = asString(h256::random().asBytes());
write(_pass, m_keysFile);
}
bool KeyManager::load(std::string const& _pass)
{
try {
bytes salt = contents(m_keysFile + ".salt");
bytes encKeys = contents(m_keysFile);
m_key = h128(pbkdf2(_pass, salt, 262144, 16));
bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys);
RLP s(bs);
unsigned version = (unsigned)s[0];
if (version == 1)
{
for (auto const& i: s[1])
m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo((h256)i[2], (std::string)i[3]);
for (auto const& i: s[2])
m_passwordInfo[(h256)i[0]] = (std::string)i[1];
m_password = (string)s[3];
}
m_cachedPasswords[hashPassword(m_password)] = m_password;
return true;
}
catch (...) {
return false;
}
}
Secret KeyManager::secret(Address const& _address, function<std::string()> const& _pass) const
{
auto it = m_addrLookup.find(_address);
if (it == m_addrLookup.end())
return Secret();
return secret(it->second, _pass);
}
Secret KeyManager::secret(h128 const& _uuid, function<std::string()> const& _pass) const
{
return Secret(m_store.secret(_uuid, [&](){
auto kit = m_keyInfo.find(_uuid);
if (kit != m_keyInfo.end())
{
auto it = m_cachedPasswords.find(kit->second.passHash);
if (it != m_cachedPasswords.end())
return it->second;
}
std::string p = _pass();
m_cachedPasswords[hashPassword(p)] = p;
return p;
}));
}
h128 KeyManager::uuid(Address const& _a) const
{
auto it = m_addrLookup.find(_a);
if (it == m_addrLookup.end())
return h128();
return it->second;
}
Address KeyManager::address(h128 const& _uuid) const
{
for (auto const& i: m_addrLookup)
if (i.second == _uuid)
return i.first;
return Address();
}
h128 KeyManager::import(Secret const& _s, string const& _info, std::string const& _pass, string const& _passInfo)
{
Address addr = KeyPair(_s).address();
auto passHash = hashPassword(_pass);
m_cachedPasswords[passHash] = _pass;
m_passwordInfo[passHash] = _passInfo;
auto uuid = m_store.importSecret(_s.asBytes(), _pass);
m_keyInfo[uuid] = KeyInfo{passHash, _info};
m_addrLookup[addr] = uuid;
write(m_keysFile);
return uuid;
}
void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo)
{
bytes key = m_store.secret(_uuid, [&](){ return _pass; });
if (key.empty())
return;
Address a = KeyPair(Secret(key)).address();
auto passHash = hashPassword(_pass);
if (!m_passwordInfo.count(passHash))
m_passwordInfo[passHash] = _passInfo;
if (!m_cachedPasswords.count(passHash))
m_cachedPasswords[passHash] = _pass;
m_addrLookup[a] = _uuid;
m_keyInfo[_uuid].passHash = passHash;
m_keyInfo[_uuid].info = _info;
write(m_keysFile);
}
void KeyManager::kill(Address const& _a)
{
auto id = m_addrLookup[_a];
m_addrLookup.erase(_a);
m_keyInfo.erase(id);
m_store.kill(id);
}
std::map<Address, std::pair<std::string, std::string>> KeyManager::keys() const
{
std::map<Address, std::pair<std::string, std::string>> ret;
for (auto const& i: m_addrLookup)
if (m_keyInfo.count(i.second) > 0)
ret[i.first] = make_pair(m_keyInfo.at(i.second).info, m_passwordInfo.at(m_keyInfo.at(i.second).passHash));
return ret;
}
h256 KeyManager::hashPassword(std::string const& _pass) const
{
// TODO SECURITY: store this a bit more securely; Scrypt perhaps?
return h256(pbkdf2(_pass, asBytes(m_password), 262144, 32));
}
bool KeyManager::write(std::string const& _keysFile) const
{
if (!m_key)
return false;
write(m_key, _keysFile);
return true;
}
void KeyManager::write(std::string const& _pass, std::string const& _keysFile) const
{
bytes salt = h256::random().asBytes();
writeFile(_keysFile + ".salt", salt);
auto key = h128(pbkdf2(_pass, salt, 262144, 16));
write(key, _keysFile);
}
void KeyManager::write(h128 const& _key, std::string const& _keysFile) const
{
RLPStream s(4);
s << 1;
s.appendList(m_addrLookup.size());
for (auto const& i: m_addrLookup)
if (m_keyInfo.count(i.second))
{
auto ki = m_keyInfo.at(i.second);
s.appendList(4) << i.first << i.second << ki.passHash << ki.info;
}
s.appendList(m_passwordInfo.size());
for (auto const& i: m_passwordInfo)
s.appendList(2) << i.first << i.second;
s.append(m_password);
writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()));
m_key = _key;
}

110
libethereum/KeyManager.h

@ -0,0 +1,110 @@
/*
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 KeyManager.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <functional>
#include <mutex>
#include <libdevcrypto/SecretStore.h>
#include <libdevcrypto/FileSystem.h>
namespace dev
{
class UnknownPassword: public Exception {};
struct KeyInfo
{
KeyInfo() = default;
KeyInfo(h256 const& _passHash, std::string const& _info): passHash(_passHash), info(_info) {}
h256 passHash;
std::string info;
};
static const auto DontKnowThrow = [](){ throw UnknownPassword(); return std::string(); };
// TODO: This one is specifically for Ethereum, but we can make it generic in due course.
// TODO: hidden-partition style key-store.
/**
* @brief High-level manager of keys for Ethereum.
* Usage:
*
* Call exists() to check whether there is already a database. If so, get the master password from
* the user and call load() with it. If not, get a new master password from the user (get them to type
* it twice and keep some hint around!) and call create() with it.
*/
class KeyManager
{
public:
KeyManager(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info");
~KeyManager();
void setKeysFile(std::string const& _keysFile) { m_keysFile = _keysFile; }
std::string const& keysFile() const { return m_keysFile; }
bool exists() const;
void create(std::string const& _pass);
bool load(std::string const& _pass);
void save(std::string const& _pass) const { write(_pass, m_keysFile); }
std::map<Address, std::pair<std::string, std::string>> keys() const;
h128 uuid(Address const& _a) const;
Address address(h128 const& _uuid) const;
h128 import(Secret const& _s, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, m_password, std::string()); }
SecretStore& store() { return m_store; }
void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
Secret secret(Address const& _address, std::function<std::string()> const& _pass = DontKnowThrow) const;
Secret secret(h128 const& _uuid, std::function<std::string()> const& _pass = DontKnowThrow) const;
void kill(h128 const& _id) { kill(address(_id)); }
void kill(Address const& _a);
private:
h256 hashPassword(std::string const& _pass) const;
// Only use if previously loaded ok.
// @returns false if wasn't previously loaded ok.
bool write(std::string const& _keysFile) const;
void write(std::string const& _pass, std::string const& _keysFile) const;
void write(h128 const& _key, std::string const& _keysFile) const;
// Ethereum keys.
std::map<Address, h128> m_addrLookup;
std::map<h128, KeyInfo> m_keyInfo;
std::map<h256, std::string> m_passwordInfo;
// Passwords that we're storing.
mutable std::map<h256, std::string> m_cachedPasswords;
// The default password for keys in the keystore - protected by the master password.
std::string m_password;
SecretStore m_store;
mutable h128 m_key;
mutable std::string m_keysFile;
};
}

4
libethereum/LogFilter.h

@ -67,8 +67,8 @@ public:
friend std::ostream& dev::eth::operator<<(std::ostream& _out, dev::eth::LogFilter const& _s);
private:
AddressSet m_addresses;
std::array<h256Set, 4> m_topics;
AddressHash m_addresses;
std::array<h256Hash, 4> m_topics;
unsigned m_earliest = 0;
unsigned m_latest = LatestBlock;
};

4
libethereum/Precompiled.cpp

@ -81,7 +81,7 @@ static bytes identityCode(bytesConstRef _in)
return _in.toBytes();
}
static const std::map<unsigned, PrecompiledAddress> c_precompiled =
static const std::unordered_map<unsigned, PrecompiledAddress> c_precompiled =
{
{ 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }},
{ 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }},
@ -89,7 +89,7 @@ static const std::map<unsigned, PrecompiledAddress> c_precompiled =
{ 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }}
};
std::map<unsigned, PrecompiledAddress> const& dev::eth::precompiled()
std::unordered_map<unsigned, PrecompiledAddress> const& dev::eth::precompiled()
{
return c_precompiled;
}

4
libethereum/Precompiled.h

@ -21,7 +21,7 @@
#pragma once
#include <map>
#include <unordered_map>
#include <functional>
#include <libdevcore/CommonData.h>
@ -38,7 +38,7 @@ struct PrecompiledAddress
};
/// Info on precompiled contract accounts baked into the protocol.
std::map<unsigned, PrecompiledAddress> const& precompiled();
std::unordered_map<unsigned, PrecompiledAddress> const& precompiled();
}
}

23
libethereum/State.cpp

@ -208,9 +208,9 @@ StateDiff State::diff(State const& _c) const
{
StateDiff ret;
std::set<Address> ads;
std::set<Address> trieAds;
std::set<Address> trieAdsD;
std::unordered_set<Address> ads;
std::unordered_set<Address> trieAds;
std::unordered_set<Address> trieAdsD;
auto trie = SecureTrieDB<Address, OverlayDB>(const_cast<OverlayDB*>(&m_db), rootHash());
auto trieD = SecureTrieDB<Address, OverlayDB>(const_cast<OverlayDB*>(&_c.m_db), _c.rootHash());
@ -246,7 +246,7 @@ void State::ensureCached(Address _a, bool _requireCode, bool _forceCreate) const
ensureCached(m_cache, _a, _requireCode, _forceCreate);
}
void State::ensureCached(std::map<Address, Account>& _cache, Address _a, bool _requireCode, bool _forceCreate) const
void State::ensureCached(std::unordered_map<Address, Account>& _cache, Address _a, bool _requireCode, bool _forceCreate) const
{
auto it = _cache.find(_a);
if (it == _cache.end())
@ -426,10 +426,10 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
return ret;
}
map<Address, u256> State::addresses() const
unordered_map<Address, u256> State::addresses() const
{
#if ETH_FATDB
map<Address, u256> ret;
unordered_map<Address, u256> ret;
for (auto i: m_cache)
if (i.second.isAlive())
ret[i.first] = i.second.balance();
@ -610,6 +610,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (receiptsTrie.root() != m_currentBlock.receiptsRoot)
{
cwarn << "Bad receipts state root.";
cwarn << "Expected: " << toString(receiptsTrie.root()) << " received: " << toString(m_currentBlock.receiptsRoot);
cwarn << "Block:" << toHex(_block);
cwarn << "Block RLP:" << rlp;
cwarn << "Calculated: " << receiptsTrie.root();
@ -649,9 +650,9 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (rlp[2].itemCount() > 2)
BOOST_THROW_EXCEPTION(TooManyUncles());
set<Nonce> nonces = { m_currentBlock.nonce };
unordered_set<Nonce> nonces = { m_currentBlock.nonce };
vector<BlockInfo> rewarded;
set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
h256Hash knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
for (auto const& i: rlp[2])
{
@ -805,7 +806,7 @@ void State::commitToMine(BlockChain const& _bc)
{
// Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations.
// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl;
set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
h256Hash knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
auto p = m_previousBlock.parentHash;
for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent)
{
@ -1016,9 +1017,9 @@ u256 State::storage(Address _id, u256 _memory) const
return ret;
}
map<u256, u256> State::storage(Address _id) const
unordered_map<u256, u256> State::storage(Address _id) const
{
map<u256, u256> ret;
unordered_map<u256, u256> ret;
ensureCached(_id, false, false);
auto it = m_cache.find(_id);

17
libethereum/State.h

@ -22,7 +22,6 @@
#pragma once
#include <array>
#include <map>
#include <unordered_map>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
@ -142,7 +141,7 @@ public:
/// @returns the set containing all addresses currently in use in Ethereum.
/// @throws InterfaceNotSupported if compiled without ETH_FATDB.
std::map<Address, u256> addresses() const;
std::unordered_map<Address, u256> addresses() const;
/// Get the header information on the present block.
BlockInfo const& info() const { return m_currentBlock; }
@ -238,8 +237,8 @@ public:
/// Get the storage of an account.
/// @note This is expensive. Don't use it unless you need to.
/// @returns std::map<u256, u256> if no account exists at that address.
std::map<u256, u256> storage(Address _contract) const;
/// @returns std::unordered_map<u256, u256> if no account exists at that address.
std::unordered_map<u256, u256> storage(Address _contract) const;
/// Get the code of an account.
/// @returns bytes() if no account exists at that address.
@ -263,7 +262,7 @@ public:
Transactions const& pending() const { return m_transactions; }
/// Get the list of hashes of pending transactions.
h256Set const& pendingHashes() const { return m_transactionSet; }
h256Hash const& pendingHashes() const { return m_transactionSet; }
/// Get the transaction receipt for the transaction of the given index.
TransactionReceipt const& receipt(unsigned _i) const { return m_receipts[_i]; }
@ -334,7 +333,7 @@ private:
void ensureCached(Address _a, bool _requireCode, bool _forceCreate) const;
/// Retrieve all information about a given address into a cache.
void ensureCached(std::map<Address, Account>& _cache, Address _a, bool _requireCode, bool _forceCreate) const;
void ensureCached(std::unordered_map<Address, Account>& _cache, Address _a, bool _requireCode, bool _forceCreate) const;
/// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
@ -355,10 +354,10 @@ private:
SecureTrieDB<Address, OverlayDB> m_state; ///< Our state tree, as an OverlayDB DB.
Transactions m_transactions; ///< The current list of transactions that we've included in the state.
TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts.
std::set<h256> m_transactionSet; ///< The set of transaction hashes that we've included in the state.
h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state.
OverlayDB m_lastTx;
mutable std::map<Address, Account> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.
mutable std::unordered_map<Address, Account> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.
BlockInfo m_previousBlock; ///< The previous block's information.
BlockInfo m_currentBlock; ///< The current block's information.
@ -380,7 +379,7 @@ private:
std::ostream& operator<<(std::ostream& _out, State const& _s);
template <class DB>
void commit(std::map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Address, DB>& _state)
void commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Address, DB>& _state)
{
for (auto const& i: _cache)
if (i.second.isDirty())

6
libethereum/Transaction.h

@ -111,10 +111,10 @@ public:
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce, Secret const& _secret): m_type(ContractCreation), m_nonce(_nonce), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); }
/// Constructs an unsigned message-call transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data): m_type(MessageCall), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {}
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce = 0): m_type(MessageCall), m_nonce(_nonce), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {}
/// Constructs an unsigned contract-creation transaction.
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data): m_type(ContractCreation), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {}
Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = 0): m_type(ContractCreation), m_nonce(_nonce), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {}
/// Constructs a transaction from the given RLP.
explicit Transaction(bytesConstRef _rlp, CheckTransaction _checkSig);
@ -132,6 +132,8 @@ public:
Address const& sender() const;
/// Like sender() but will never throw. @returns a null Address if the signature is invalid.
Address const& safeSender() const noexcept;
/// Force the sender to a particular value. This will result in an invalid transaction RLP.
void forceSender(Address const& _a) { m_sender = _a; }
/// @returns true if transaction is non-null.
explicit operator bool() const { return m_type != NullTransaction; }

18
libethereum/TransactionQueue.h

@ -55,7 +55,7 @@ public:
void drop(h256 const& _txHash);
std::map<h256, Transaction> transactions() const { ReadGuard l(m_lock); return m_current; }
std::unordered_map<h256, Transaction> transactions() const { ReadGuard l(m_lock); return m_current; }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); }
u256 maxNonce(Address const& _a) const;
@ -72,14 +72,14 @@ private:
void insertCurrent_WITH_LOCK(std::pair<h256, Transaction> const& _p);
bool removeCurrent_WITH_LOCK(h256 const& _txHash);
mutable SharedMutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets.
std::map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx.
std::multimap<Address, std::pair<h256, Transaction>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
std::map<h256, std::function<void(ImportResult)>> m_callbacks; ///< Called once.
std::set<h256> m_dropped; ///< Transactions that have previously been dropped.
std::multimap<Address, h256> m_senders; ///< Mapping from the sender address to the transaction hash; useful for determining the nonce of a given sender.
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast.
mutable SharedMutex m_lock; ///< General lock.
h256Hash m_known; ///< Hashes of transactions in both sets.
std::unordered_map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx.
std::unordered_multimap<Address, std::pair<h256, Transaction>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
std::unordered_map<h256, std::function<void(ImportResult)>> m_callbacks; ///< Called once.
h256Hash m_dropped; ///< Transactions that have previously been dropped.
std::multimap<Address, h256> m_senders; ///< Mapping from the sender address to the transaction hash; useful for determining the nonce of a given sender.
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast.
};
}

1
libethereum/TransactionReceipt.h

@ -22,7 +22,6 @@
#pragma once
#include <array>
#include <map>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libevm/ExtVMFace.h>

2
libethereumx/Ethereum.cpp

@ -87,7 +87,7 @@ void Ethereum::submitTransaction(Secret _secret, u256 _value, Address _dest, byt
{
}
bytes Ethereum::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
bytes Ethereum::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
return bytes();
}

2
libethereumx/Ethereum.h

@ -75,7 +75,7 @@ public:
void flushTransactions();
/// Makes the given call. Nothing is recorded into the state.
bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
bytes call(Address const& _from, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
// Informational stuff

30
libjsconsole/CMakeLists.txt

@ -0,0 +1,30 @@
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 ${V8_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${READLINE_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
set(EXECUTABLE jsconsole)
file(GLOB HEADERS "*.h")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} jsengine)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
target_link_libraries(${EXECUTABLE} web3jsonrpc)
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

86
libjsconsole/JSConsole.cpp

@ -0,0 +1,86 @@
/*
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 JSConsole.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include <iostream>
#include <libdevcore/Log.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include "JSConsole.h"
#include "JSV8Connector.h"
#include "libjsconsole/JSConsoleResources.hpp"
// TODO! make readline optional!
#include <readline/readline.h>
#include <readline/history.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
JSConsole::JSConsole(WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts):
m_engine(),
m_printer(m_engine)
{
m_jsonrpcConnector.reset(new JSV8Connector(m_engine));
m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts));
}
JSConsole::~JSConsole() {}
void JSConsole::repl() const
{
string cmd = "";
g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << flush; rl_forced_update_display(); };
bool isEmpty = true;
int openBrackets = 0;
do {
char* buff = readline(promptForIndentionLevel(openBrackets).c_str());
isEmpty = !(buff && *buff);
if (!isEmpty)
{
cmd += string(buff);
cmd += " ";
free(buff);
int open = count(cmd.begin(), cmd.end(), '{');
open += count(cmd.begin(), cmd.end(), '(');
int closed = count(cmd.begin(), cmd.end(), '}');
closed += count(cmd.begin(), cmd.end(), ')');
openBrackets = open - closed;
}
} while (openBrackets > 0);
if (!isEmpty)
{
add_history(cmd.c_str());
auto value = m_engine.eval(cmd.c_str());
string result = m_printer.prettyPrint(value).cstr();
cout << result << endl;
}
}
std::string JSConsole::promptForIndentionLevel(int _i) const
{
if (_i == 0)
return "> ";
return string((_i + 1) * 2, ' ');
}

53
libjsconsole/JSConsole.h

@ -0,0 +1,53 @@
/*
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 JSConsole.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include <libjsengine/JSV8Engine.h>
#include <libjsengine/JSV8Printer.h>
class WebThreeStubServer;
namespace jsonrpc { class AbstractServerConnector; }
namespace dev
{
namespace eth
{
class JSConsole
{
public:
JSConsole(WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts);
~JSConsole();
void repl() const;
private:
std::string promptForIndentionLevel(int _i) const;
JSV8Engine m_engine;
JSV8Printer m_printer;
std::unique_ptr<WebThreeStubServer> m_jsonrpcServer;
std::unique_ptr<jsonrpc::AbstractServerConnector> m_jsonrpcConnector;
};
}
}

54
libjsconsole/JSV8Connector.cpp

@ -0,0 +1,54 @@
/*
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 JSV8Connector.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include "JSV8Connector.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
bool JSV8Connector::StartListening()
{
return true;
}
bool JSV8Connector::StopListening()
{
return true;
}
bool JSV8Connector::SendResponse(std::string const& _response, void* _addInfo)
{
(void)_addInfo;
m_lastResponse = _response.c_str();
return true;
}
void JSV8Connector::onSend(char const* payload)
{
OnRequest(payload, NULL);
}
JSV8Connector::~JSV8Connector()
{
StopListening();
}

50
libjsconsole/JSV8Connector.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 JSV8Connector.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include <jsonrpccpp/server/abstractserverconnector.h>
#include <libjsengine/JSV8RPC.h>
namespace dev
{
namespace eth
{
class JSV8Connector: public jsonrpc::AbstractServerConnector, public JSV8RPC
{
public:
JSV8Connector(JSV8Engine const& _engine): JSV8RPC(_engine) {}
virtual ~JSV8Connector();
// implement AbstractServerConnector interface
bool StartListening();
bool StopListening();
bool SendResponse(std::string const& _response, void* _addInfo = nullptr);
// implement JSV8RPC interface
void onSend(char const* payload);
};
}
}

36
libjsengine/CMakeLists.txt

@ -0,0 +1,36 @@
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 ${V8_INCLUDE_DIRS})
include_directories(BEFORE ..)
set(EXECUTABLE jsengine)
file(GLOB HEADERS "*.h")
include(EthUtils)
eth_add_resources("${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake" "JSRES")
message(STATUS "HERE!!! ${JSRES}")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES})
# macos brew version of v8 needs to be compiled with libstdc++
# it also needs to be dynamic library
# xcode needs libstdc++ to be explicitly set as it's attribute
if (APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
set_property(TARGET ${EXECUTABLE} PROPERTY XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libstdc++")
endif()
target_link_libraries(${EXECUTABLE} ${V8_LIBRARIES})
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

11
libjsengine/Common.js

@ -0,0 +1,11 @@
console = {};
console.log = function () {
};
console.warn = function () {
};
console.error = function () {
};
setTimeout = function () {
};

36
libjsengine/JSEngine.cpp

@ -0,0 +1,36 @@
/*
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 JSEngine.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include <string.h>
#include <stdlib.h>
#include "JSEngine.h"
using namespace dev;
using namespace dev::eth;
JSString::JSString(char const* _cstr): m_cstr(strdup(_cstr)) {}
JSString::~JSString()
{
if (m_cstr)
free(m_cstr);
}

60
libjsengine/JSEngine.h

@ -0,0 +1,60 @@
/*
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 JSEngine.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include <exception>
namespace dev
{
namespace eth
{
class JSException: public std::exception {};
class JSPrintException: public JSException { char const* what() const noexcept { return "Cannot print expression!"; } };
class JSString
{
public:
JSString(char const* _cstr);
~JSString();
char const* cstr() const { return m_cstr; }
private:
char* m_cstr;
};
class JSValue
{
public:
virtual JSString toString() const = 0;
};
template <typename T>
class JSEngine
{
public:
// should be used to evalute javascript expression
virtual T eval(char const* _cstr) const = 0;
};
}
}

23
libjsengine/JSPrinter.cpp

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

41
libjsengine/JSPrinter.h

@ -0,0 +1,41 @@
/*
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 JSPrinter.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include "JSEngine.h"
namespace dev
{
namespace eth
{
template <typename T>
class JSPrinter
{
public:
virtual JSString print(T const& _value) const { return _value.toString(); }
virtual JSString prettyPrint(T const& _value) const { return print(_value); }
};
}
}

8
libjsengine/JSResources.cmake

@ -0,0 +1,8 @@
set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js")
set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js")
set(common "${CMAKE_CURRENT_LIST_DIR}/Common.js")
set(ETH_RESOURCE_NAME "JSEngineResources")
set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}")
set(ETH_RESOURCES "web3" "pretty_print" "common")

187
libjsengine/JSV8Engine.cpp

@ -0,0 +1,187 @@
/*
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 JSV8Engine.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include <memory>
#include "JSV8Engine.h"
#include "libjsengine/JSEngineResources.hpp"
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace dev
{
namespace eth
{
static char const* toCString(v8::String::Utf8Value const& _value)
{
if (*_value)
return *_value;
throw JSPrintException();
}
// from: https://github.com/v8/v8-git-mirror/blob/master/samples/shell.cc
// v3.15 from: https://chromium.googlesource.com/v8/v8.git/+/3.14.5.9/samples/shell.cc
void reportException(v8::TryCatch* _tryCatch)
{
v8::HandleScope handle_scope;
v8::String::Utf8Value exception(_tryCatch->Exception());
char const* exceptionString = toCString(exception);
v8::Handle<v8::Message> message = _tryCatch->Message();
// V8 didn't provide any extra information about this error; just
// print the exception.
if (message.IsEmpty())
printf("%s\n", exceptionString);
else
{
// Print (filename):(line number): (message).
v8::String::Utf8Value filename(message->GetScriptResourceName());
char const* filenameString = toCString(filename);
int linenum = message->GetLineNumber();
printf("%s:%i: %s\n", filenameString, linenum, exceptionString);
// Print line of source code.
v8::String::Utf8Value sourceline(message->GetSourceLine());
char const* sourcelineString = toCString(sourceline);
printf("%s\n", sourcelineString);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
for (int i = 0; i < start; i++)
printf(" ");
int end = message->GetEndColumn();
for (int i = start; i < end; i++)
printf("^");
printf("\n");
v8::String::Utf8Value stackTrace(_tryCatch->StackTrace());
if (stackTrace.length() > 0)
{
char const* stackTraceString = toCString(stackTrace);
printf("%s\n", stackTraceString);
}
}
}
class JSV8Env
{
public:
~JSV8Env()
{
v8::V8::Dispose();
}
};
class JSV8Scope
{
public:
JSV8Scope():
m_handleScope(),
m_context(v8::Context::New(NULL, v8::ObjectTemplate::New())),
m_contextScope(m_context)
{
m_context->Enter();
}
~JSV8Scope()
{
m_context->Exit();
m_context.Dispose();
}
v8::Persistent <v8::Context> const& context() const { return m_context; }
private:
v8::HandleScope m_handleScope;
v8::Persistent <v8::Context> m_context;
v8::Context::Scope m_contextScope;
};
}
}
JSV8Env JSV8Engine::s_env = JSV8Env();
JSString JSV8Value::toString() const
{
if (m_value.IsEmpty())
return "";
else if (m_value->IsUndefined())
return "undefined";
v8::String::Utf8Value str(m_value);
return toCString(str);
}
JSV8Engine::JSV8Engine(): m_scope(new JSV8Scope())
{
JSEngineResources resources;
string common = resources.loadResourceAsString("common");
string web3 = resources.loadResourceAsString("web3");
eval(common.c_str());
eval(web3.c_str());
eval("web3 = require('web3');");
}
JSV8Engine::~JSV8Engine()
{
delete m_scope;
}
JSV8Value JSV8Engine::eval(char const* _cstr) const
{
v8::HandleScope handleScope;
v8::TryCatch tryCatch;
v8::Local<v8::String> source = v8::String::New(_cstr);
v8::Local<v8::String> name(v8::String::New("(shell)"));
v8::ScriptOrigin origin(name);
v8::Handle<v8::Script> script = v8::Script::Compile(source, &origin);
// Make sure to wrap the exception in a new handle because
// the handle returned from the TryCatch is destroyed
if (script.IsEmpty())
{
reportException(&tryCatch);
return v8::Exception::Error(v8::Local<v8::String>::New(tryCatch.Message()->Get()));
}
auto result = script->Run();
if (result.IsEmpty())
{
reportException(&tryCatch);
return v8::Exception::Error(v8::Local<v8::String>::New(tryCatch.Message()->Get()));
}
return result;
}
v8::Handle<v8::Context> const& JSV8Engine::context() const
{
return m_scope->context();
}

61
libjsengine/JSV8Engine.h

@ -0,0 +1,61 @@
/*
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 JSV8Engine.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include <v8.h>
#include "JSEngine.h"
namespace dev
{
namespace eth
{
class JSV8Env;
class JSV8Scope;
class JSV8Value: public JSValue
{
public:
JSV8Value(v8::Handle<v8::Value> _value): m_value(_value) {}
JSString toString() const;
v8::Handle<v8::Value> const& value() const { return m_value; }
private:
v8::Handle<v8::Value> m_value;
};
class JSV8Engine: public JSEngine<JSV8Value>
{
public:
JSV8Engine();
virtual ~JSV8Engine();
JSV8Value eval(char const* _cstr) const;
v8::Handle<v8::Context> const& context() const;
private:
static JSV8Env s_env;
JSV8Scope* m_scope;
};
}
}

49
libjsengine/JSV8Printer.cpp

@ -0,0 +1,49 @@
/*
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 JSV8Printer.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include <string>
#include "JSV8Printer.h"
#include "libjsengine/JSEngineResources.hpp"
using namespace std;
using namespace dev;
using namespace eth;
JSV8Printer::JSV8Printer(JSV8Engine const& _engine): m_engine(_engine)
{
JSEngineResources resources;
string prettyPrint = resources.loadResourceAsString("pretty_print");
m_engine.eval(prettyPrint.c_str());
}
JSString JSV8Printer::prettyPrint(JSV8Value const& _value) const
{
v8::HandleScope handleScope;
v8::Local<v8::String> pp = v8::String::New("prettyPrint");
v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(m_engine.context()->Global()->Get(pp));
v8::Local<v8::Value> values[1] = {v8::Local<v8::Value>::New(_value.value())};
v8::Local<v8::Value> res = func->Call(func, 1, values);
v8::String::Utf8Value str(res);
if (*str)
return *str;
throw JSPrintException();
}

43
libjsengine/JSV8Printer.h

@ -0,0 +1,43 @@
/*
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 JSV8Printer.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include "JSPrinter.h"
#include "JSV8Engine.h"
namespace dev
{
namespace eth
{
class JSV8Printer: public JSPrinter<JSV8Value>
{
public:
JSV8Printer(JSV8Engine const& _engine);
JSString prettyPrint(JSV8Value const& _value) const;
private:
JSV8Engine const& m_engine;
};
}
}

84
libjsengine/JSV8RPC.cpp

@ -0,0 +1,84 @@
/*
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 JSV8RPC.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#include "JSV8RPC.h"
using namespace dev;
using namespace dev::eth;
namespace dev
{
namespace eth
{
v8::Handle<v8::Value> JSV8RPCSend(v8::Arguments const& _args)
{
v8::Local<v8::String> JSON = v8::String::New("JSON");
v8::Local<v8::String> parse = v8::String::New("parse");
v8::Local<v8::String> stringify = v8::String::New("stringify");
v8::Handle<v8::Object> jsonObject = v8::Handle<v8::Object>::Cast(v8::Context::GetCurrent()->Global()->Get(JSON));
v8::Handle<v8::Function> parseFunc = v8::Handle<v8::Function>::Cast(jsonObject->Get(parse));
v8::Handle<v8::Function> stringifyFunc = v8::Handle<v8::Function>::Cast(jsonObject->Get(stringify));
v8::Local<v8::Object> self = _args.Holder();
v8::Local<v8::External> wrap = v8::Local<v8::External>::Cast(self->GetInternalField(0));
JSV8RPC* that = static_cast<JSV8RPC*>(wrap->Value());
v8::Local<v8::Value> vals[1] = {_args[0]->ToObject()};
v8::Local<v8::Value> stringifiedArg = stringifyFunc->Call(stringifyFunc, 1, vals);
v8::String::Utf8Value str(stringifiedArg);
that->onSend(*str);
v8::Local<v8::Value> values[1] = {v8::String::New(that->lastResponse())};
return parseFunc->Call(parseFunc, 1, values);
}
}
}
JSV8RPC::JSV8RPC(JSV8Engine const& _engine): m_engine(_engine)
{
v8::HandleScope scope;
v8::Local<v8::ObjectTemplate> rpcTemplate = v8::ObjectTemplate::New();
rpcTemplate->SetInternalFieldCount(1);
rpcTemplate->Set(v8::String::New("send"),
v8::FunctionTemplate::New(JSV8RPCSend));
rpcTemplate->Set(v8::String::New("sendAsync"),
v8::FunctionTemplate::New(JSV8RPCSend));
v8::Local<v8::Object> obj = rpcTemplate->NewInstance();
obj->SetInternalField(0, v8::External::New(this));
v8::Local<v8::String> web3 = v8::String::New("web3");
v8::Local<v8::String> setProvider = v8::String::New("setProvider");
v8::Handle<v8::Object> web3object = v8::Handle<v8::Object>::Cast(m_engine.context()->Global()->Get(web3));
v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(web3object->Get(setProvider));
v8::Local<v8::Value> values[1] = {obj};
func->Call(func, 1, values);
m_lastResponse = R"(
{
"id": 1,
"jsonrpc": "2.0",
"error": "Uninitalized JSV8RPC!"
}
)";
}

47
libjsengine/JSV8RPC.h

@ -0,0 +1,47 @@
/*
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 JSV8RPC.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
* Ethereum client.
*/
#pragma once
#include <libjsengine/JSV8Engine.h>
namespace dev
{
namespace eth
{
class JSV8RPC
{
public:
JSV8RPC(JSV8Engine const& _engine);
virtual void onSend(char const* _payload) = 0;
char const* lastResponse() const { return m_lastResponse; }
private:
JSV8Engine const& m_engine;
protected:
char const* m_lastResponse;
};
}
}

91
libjsengine/PrettyPrint.js

@ -0,0 +1,91 @@
var prettyPrint = (function () {
function pp(object, indent) {
try {
JSON.stringify(object)
} catch(e) {
return pp(e, indent);
}
var str = "";
if(object instanceof Array) {
str += "[";
for(var i = 0, l = object.length; i < l; i++) {
str += pp(object[i], indent);
if(i < l-1) {
str += ", ";
}
}
str += " ]";
} else if (object instanceof Error) {
str += "\033[31m" + "Error:\033[0m " + object.message;
} else if (object === null) {
str += "\033[1m\033[30m" + "null";
} else if(typeof(object) === "undefined") {
str += "\033[1m\033[30m" + object;
} else if (isBigNumber(object)) {
str += "\033[32m'" + object.toString(10) + "'";
} else if(typeof(object) === "object") {
str += "{\n";
indent += " ";
var last = getFields(object).pop()
getFields(object).forEach(function (k) {
str += indent + k + ": ";
try {
str += pp(object[k], indent);
} catch (e) {
str += pp(e, indent);
}
if(k !== last) {
str += ",";
}
str += "\n";
});
str += indent.substr(2, indent.length) + "}";
} else if(typeof(object) === "string") {
str += "\033[32m'" + object + "'";
} else if(typeof(object) === "number") {
str += "\033[31m" + object;
} else if(typeof(object) === "function") {
str += "\033[35m[Function]";
} else {
str += object;
}
str += "\033[0m";
return str;
}
var redundantFields = [
'valueOf',
'toString',
'toLocaleString',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor',
'__defineGetter__',
'__defineSetter__',
'__lookupGetter__',
'__lookupSetter__',
'__proto__'
];
var getFields = function (object) {
var result = Object.getOwnPropertyNames(object);
if (object.constructor && object.constructor.prototype) {
result = result.concat(Object.getOwnPropertyNames(object.constructor.prototype));
}
return result.filter(function (field) {
return redundantFields.indexOf(field) === -1;
});
};
var isBigNumber = function (object) {
return (!!object.constructor && object.constructor.name === 'BigNumber') ||
(typeof BigNumber !== 'undefined' && object instanceof BigNumber)
};
function prettyPrintInner(/* */) {
var args = arguments;
var ret = "";
for(var i = 0, l = args.length; i < l; i++) {
ret += pp(args[i], "") + "\n";
}
return ret;
};
return prettyPrintInner;
})();

23
libp2p/Common.h

@ -214,3 +214,26 @@ struct Node
/// Simple stream output for a NodeIPEndpoint.
std::ostream& operator<<(std::ostream& _out, dev::p2p::NodeIPEndpoint const& _ep);
}
/// std::hash for asio::adress
namespace std
{
template <> struct hash<bi::address>
{
size_t operator()(bi::address const& _a) const
{
if (_a.is_v4())
return std::hash<unsigned long>()(_a.to_v4().to_ulong());
if (_a.is_v6())
{
auto const& range = _a.to_v6().to_bytes();
return boost::hash_range(range.begin(), range.end());
}
if (_a.is_unspecified())
return static_cast<size_t>(0x3487194039229152ul); // Chosen by fair dice roll, guaranteed to be random
return std::hash<std::string>()(_a.to_string());
}
};
}

4
libp2p/Host.h

@ -227,7 +227,7 @@ private:
std::shared_ptr<NodeTable> m_nodeTable; ///< Node table (uses kademlia-like discovery).
/// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer;
std::map<NodeId, std::shared_ptr<Peer>> m_peers;
std::unordered_map<NodeId, std::shared_ptr<Peer>> m_peers;
/// Peers we try to connect regardless of p2p network.
std::set<NodeId> m_requiredPeers;
@ -235,7 +235,7 @@ private:
/// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run())
/// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
mutable std::map<NodeId, std::weak_ptr<Session>> m_sessions;
mutable std::unordered_map<NodeId, std::weak_ptr<Session>> m_sessions;
mutable RecursiveMutex x_sessions;
std::list<std::weak_ptr<RLPXHandshake>> m_connecting; ///< Pending connections.

2
libp2p/Network.cpp

@ -154,12 +154,12 @@ int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const&
_acceptor.bind(endpoint);
_acceptor.listen();
retport = _acceptor.local_endpoint().port();
assert(retport == _netPrefs.listenPort);
}
catch (...)
{
clog(NetWarn) << "Couldn't start accepting connections on host. Failed to accept socket.\n" << boost::current_exception_diagnostic_information();
}
assert(retport == _netPrefs.listenPort);
return retport;
}
return retport;

36
libp2p/NodeTable.h

@ -80,7 +80,7 @@ protected:
Mutex x_events;
std::list<NodeId> m_nodeEventHandler;
std::map<NodeId, NodeTableEventType> m_events;
std::unordered_map<NodeId, NodeTableEventType> m_events;
};
class NodeTable;
@ -243,32 +243,32 @@ private:
/// Purges and pings nodes for any buckets which haven't been touched for c_bucketRefresh seconds.
void doRefreshBuckets(boost::system::error_code const& _ec);
std::unique_ptr<NodeTableEventHandler> m_nodeEventHandler; ///< Event handler for node events.
std::unique_ptr<NodeTableEventHandler> m_nodeEventHandler; ///< Event handler for node events.
Node m_node; ///< This node.
Secret m_secret; ///< This nodes secret key.
Node m_node; ///< This node.
Secret m_secret; ///< This nodes secret key.
mutable Mutex x_nodes; ///< LOCK x_state first if both locks are required. Mutable for thread-safe copy in nodes() const.
std::map<NodeId, std::shared_ptr<NodeEntry>> m_nodes; ///< Nodes
mutable Mutex x_nodes; ///< LOCK x_state first if both locks are required. Mutable for thread-safe copy in nodes() const.
std::unordered_map<NodeId, std::shared_ptr<NodeEntry>> m_nodes; ///< Nodes
mutable Mutex x_state; ///< LOCK x_state first if both x_nodes and x_state locks are required.
std::array<NodeBucket, s_bins> m_state; ///< State of p2p node network.
mutable Mutex x_state; ///< LOCK x_state first if both x_nodes and x_state locks are required.
std::array<NodeBucket, s_bins> m_state; ///< State of p2p node network.
Mutex x_evictions; ///< LOCK x_evictions first if both x_nodes and x_evictions locks are required.
std::deque<EvictionTimeout> m_evictions; ///< Eviction timeouts.
Mutex x_evictions; ///< LOCK x_evictions first if both x_nodes and x_evictions locks are required.
std::deque<EvictionTimeout> m_evictions; ///< Eviction timeouts.
Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required.
std::map<bi::address, TimePoint> m_pubkDiscoverPings; ///< List of pending pings where node entry wasn't created due to unkown pubk.
Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required.
std::unordered_map<bi::address, TimePoint> m_pubkDiscoverPings; ///< List of pending pings where node entry wasn't created due to unkown pubk.
Mutex x_findNodeTimeout;
std::list<NodeIdTimePoint> m_findNodeTimeout; ///< Timeouts for pending Ping and FindNode requests.
std::list<NodeIdTimePoint> m_findNodeTimeout; ///< Timeouts for pending Ping and FindNode requests.
ba::io_service& m_io; ///< Used by bucket refresh timer.
std::shared_ptr<NodeSocket> m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr.
NodeSocket* m_socketPointer; ///< Set to m_socket.get(). Socket is created in constructor and disconnected in destructor to ensure access to pointer is safe.
ba::io_service& m_io; ///< Used by bucket refresh timer.
std::shared_ptr<NodeSocket> m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr.
NodeSocket* m_socketPointer; ///< Set to m_socket.get(). Socket is created in constructor and disconnected in destructor to ensure access to pointer is safe.
boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh.
boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions.
boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh.
boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions.
};
inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable)

2
libsolidity/ASTPrinter.h

@ -42,7 +42,7 @@ public:
ASTPrinter(
ASTNode const& _ast,
std::string const& _source = std::string(),
StructuralGasEstimator::ASTGasConsumption const& _gasCosts = {}
StructuralGasEstimator::ASTGasConsumption const& _gasCosts = StructuralGasEstimator::ASTGasConsumption()
);
/// Output the string representation of the AST to _stream.
void print(std::ostream& _stream);

66
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -298,16 +298,16 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message
}
WebThreeStubServerBase::WebThreeStubServerBase(AbstractServerConnector& _conn, vector<dev::KeyPair> const& _accounts):
AbstractWebThreeStubServer(_conn), m_accounts(make_shared<AccountHolder>(bind(&WebThreeStubServerBase::client, this)))
AbstractWebThreeStubServer(_conn), m_ethAccounts(make_shared<AccountHolder>(bind(&WebThreeStubServerBase::client, this)))
{
m_accounts->setAccounts(_accounts);
m_ethAccounts->setAccounts(_accounts);
}
void WebThreeStubServerBase::setIdentities(vector<dev::KeyPair> const& _ids)
{
m_ids.clear();
m_shhIds.clear();
for (auto i: _ids)
m_ids[i.pub()] = i.secret();
m_shhIds[i.pub()] = i.secret();
}
string WebThreeStubServerBase::web3_sha3(string const& _param1)
@ -353,7 +353,7 @@ string WebThreeStubServerBase::eth_gasPrice()
Json::Value WebThreeStubServerBase::eth_accounts()
{
Json::Value ret(Json::arrayValue);
for (auto const& i: m_accounts->getAllAccounts())
for (auto const& i: m_ethAccounts->getAllAccounts())
ret.append(toJS(i));
return ret;
}
@ -499,7 +499,7 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
TransactionSkeleton t = toTransaction(_json);
if (!t.from)
t.from = m_accounts->getDefaultTransactAccount();
t.from = m_ethAccounts->getDefaultTransactAccount();
if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (t.gasPrice == UndefinedU256)
@ -507,9 +507,9 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
if (t.gas == UndefinedU256)
t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
if (m_accounts->isRealAccount(t.from))
if (m_ethAccounts->isRealAccount(t.from))
authenticate(t, false);
else if (m_accounts->isProxyAccount(t.from))
else if (m_ethAccounts->isProxyAccount(t.from))
authenticate(t, true);
return ret;
@ -528,17 +528,17 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json)
TransactionSkeleton t = toTransaction(_json);
if (!t.from)
t.from = m_accounts->getDefaultTransactAccount();
t.from = m_ethAccounts->getDefaultTransactAccount();
if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (!t.gasPrice)
if (t.gasPrice == UndefinedU256)
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (!t.gas)
if (t.gas == UndefinedU256)
t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
if (m_accounts->isRealAccount(t.from))
if (m_ethAccounts->isRealAccount(t.from))
authenticate(t, false);
else if (m_accounts->isProxyAccount(t.from))
else if (m_ethAccounts->isProxyAccount(t.from))
authenticate(t, true);
return toJS((t.creation ? Transaction(t.value, t.gasPrice, t.gas, t.data) : Transaction(t.value, t.gasPrice, t.gas, t.to, t.data)).sha3(WithoutSignature));
@ -579,15 +579,15 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const&
{
TransactionSkeleton t = toTransaction(_json);
if (!t.from)
t.from = m_accounts->getDefaultTransactAccount();
t.from = m_ethAccounts->getDefaultTransactAccount();
// if (!m_accounts->isRealAccount(t.from))
// return ret;
if (!t.gasPrice)
if (t.gasPrice == UndefinedU256)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
if (t.gas == UndefinedU256)
t.gas = client()->gasLimitRemaining();
return toJS(client()->call(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice, jsToBlockNumber(_blockNumber), FudgeFactor::Lenient).output);
return toJS(client()->call(t.from, t.value, t.to, t.data, t.gas, t.gasPrice, jsToBlockNumber(_blockNumber), FudgeFactor::Lenient).output);
}
catch (...)
{
@ -879,7 +879,7 @@ string WebThreeStubServerBase::eth_register(string const& _address)
{
try
{
return toJS(m_accounts->addProxyAccount(jsToAddress(_address)));
return toJS(m_ethAccounts->addProxyAccount(jsToAddress(_address)));
}
catch (...)
{
@ -891,7 +891,7 @@ bool WebThreeStubServerBase::eth_unregister(string const& _accountId)
{
try
{
return m_accounts->removeProxyAccount(jsToInt(_accountId));
return m_ethAccounts->removeProxyAccount(jsToInt(_accountId));
}
catch (...)
{
@ -906,9 +906,9 @@ Json::Value WebThreeStubServerBase::eth_fetchQueuedTransactions(string const& _a
auto id = jsToInt(_accountId);
Json::Value ret(Json::arrayValue);
// TODO: throw an error on no account with given id
for (TransactionSkeleton const& t: m_accounts->getQueuedTransactions(id))
for (TransactionSkeleton const& t: m_ethAccounts->getQueuedTransactions(id))
ret.append(toJson(t));
m_accounts->clearQueue(id);
m_ethAccounts->clearQueue(id);
return ret;
}
catch (...)
@ -934,11 +934,11 @@ bool WebThreeStubServerBase::shh_post(Json::Value const& _json)
{
shh::Message m = toMessage(_json);
Secret from;
if (m.from() && m_ids.count(m.from()))
if (m.from() && m_shhIds.count(m.from()))
{
cwarn << "Silently signing message from identity" << m.from() << ": User validation hook goes here.";
// TODO: insert validification hook here.
from = m_ids[m.from()];
from = m_shhIds[m.from()];
}
face()->inject(toSealed(_json, m, from));
@ -953,7 +953,7 @@ bool WebThreeStubServerBase::shh_post(Json::Value const& _json)
string WebThreeStubServerBase::shh_newIdentity()
{
KeyPair kp = KeyPair::create();
m_ids[kp.pub()] = kp.secret();
m_shhIds[kp.pub()] = kp.secret();
return toJS(kp.pub());
}
@ -961,7 +961,7 @@ bool WebThreeStubServerBase::shh_hasIdentity(string const& _identity)
{
try
{
return m_ids.count(jsToPublic(_identity)) > 0;
return m_shhIds.count(jsToPublic(_identity)) > 0;
}
catch (...)
{
@ -1021,7 +1021,7 @@ Json::Value WebThreeStubServerBase::shh_getFilterChanges(string const& _filterId
int id = jsToInt(_filterId);
auto pub = m_shhWatches[id];
if (!pub || m_ids.count(pub))
if (!pub || m_shhIds.count(pub))
for (h256 const& h: face()->checkWatch(id))
{
auto e = face()->envelope(h);
@ -1029,7 +1029,7 @@ Json::Value WebThreeStubServerBase::shh_getFilterChanges(string const& _filterId
if (pub)
{
cwarn << "Silently decrypting message from identity" << pub << ": User validation hook goes here.";
m = e.open(face()->fullTopic(id), m_ids[pub]);
m = e.open(face()->fullTopic(id), m_shhIds[pub]);
}
else
m = e.open(face()->fullTopic(id));
@ -1054,7 +1054,7 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId)
int id = jsToInt(_filterId);
auto pub = m_shhWatches[id];
if (!pub || m_ids.count(pub))
if (!pub || m_shhIds.count(pub))
for (h256 const& h: face()->watchMessages(id))
{
auto e = face()->envelope(h);
@ -1062,7 +1062,7 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId)
if (pub)
{
cwarn << "Silently decrypting message from identity" << pub << ": User validation hook goes here.";
m = e.open(face()->fullTopic(id), m_ids[pub]);
m = e.open(face()->fullTopic(id), m_shhIds[pub]);
}
else
m = e.open(face()->fullTopic(id));
@ -1081,14 +1081,14 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId)
void WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool _toProxy)
{
if (_toProxy)
m_accounts->queueTransaction(_t);
m_ethAccounts->queueTransaction(_t);
else if (_t.to)
client()->submitTransaction(m_accounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice);
client()->submitTransaction(m_ethAccounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice);
else
client()->submitTransaction(m_accounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice);
client()->submitTransaction(m_ethAccounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice);
}
void WebThreeStubServerBase::setAccounts(const vector<KeyPair>& _accounts)
{
m_accounts->setAccounts(_accounts);
m_ethAccounts->setAccounts(_accounts);
}

7
libweb3jsonrpc/WebThreeStubServerBase.h

@ -136,7 +136,7 @@ public:
void setAccounts(std::vector<dev::KeyPair> const& _accounts);
void setIdentities(std::vector<dev::KeyPair> const& _ids);
std::map<dev::Public, dev::Secret> const& ids() const { return m_ids; }
std::map<dev::Public, dev::Secret> const& ids() const { return m_shhIds; }
protected:
virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
@ -147,9 +147,10 @@ protected:
virtual dev::WebThreeNetworkFace* network() = 0;
virtual dev::WebThreeStubDatabaseFace* db() = 0;
std::map<dev::Public, dev::Secret> m_ids;
std::shared_ptr<dev::AccountHolder> m_ethAccounts;
std::map<dev::Public, dev::Secret> m_shhIds;
std::map<unsigned, dev::Public> m_shhWatches;
std::shared_ptr<dev::AccountHolder> m_accounts;
};
} //namespace dev

6
mix/ClientModel.cpp

@ -211,7 +211,7 @@ void ClientModel::setupState(QVariantMap _state)
QVariantList stateContracts = _state.value("contracts").toList();
QVariantList transactions = _state.value("transactions").toList();
map<Address, Account> accounts;
unordered_map<Address, Account> accounts;
std::vector<KeyPair> userAccounts;
for (auto const& b: stateAccounts)
@ -284,7 +284,7 @@ void ClientModel::setupState(QVariantMap _state)
executeSequence(transactionSequence, accounts, Secret(_state.value("miner").toMap().value("secret").toString().toStdString()));
}
void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence, std::map<Address, Account> const& _accounts, Secret const& _miner)
void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence, std::unordered_map<Address, Account> const& _accounts, Secret const& _miner)
{
if (m_running)
{
@ -551,7 +551,7 @@ QVariant ClientModel::formatValue(SolidityType const& _type, u256 const& _value)
return res;
}
QVariant ClientModel::formatStorageValue(SolidityType const& _type, map<u256, u256> const& _storage, unsigned _offset, u256 const& _slot)
QVariant ClientModel::formatStorageValue(SolidityType const& _type, unordered_map<u256, u256> const& _storage, unsigned _offset, u256 const& _slot)
{
u256 slot = _slot;
QVariantList values;

4
mix/ClientModel.h

@ -220,14 +220,14 @@ private:
RecordLogEntry* lastBlock() const;
QVariantMap contractAddresses() const;
QVariantList gasCosts() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence, std::map<Address, dev::eth::Account> const& _accounts, Secret const& _miner);
void executeSequence(std::vector<TransactionSettings> const& _sequence, std::unordered_map<Address, dev::eth::Account> const& _accounts, Secret const& _miner);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
void onNewTransaction();
void onStateReset();
void showDebuggerForTransaction(ExecutionResult const& _t);
QVariant formatValue(SolidityType const& _type, dev::u256 const& _value);
QVariant formatStorageValue(SolidityType const& _type, std::map<dev::u256, dev::u256> const& _storage, unsigned _offset, dev::u256 const& _slot);
QVariant formatStorageValue(SolidityType const& _type, std::unordered_map<dev::u256, dev::u256> const& _storage, unsigned _offset, dev::u256 const& _slot);
std::atomic<bool> m_running;
std::atomic<bool> m_mining;

2
mix/MachineStates.h

@ -50,7 +50,7 @@ namespace mix
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::unordered_map<dev::u256, dev::u256> storage;
std::vector<unsigned> levels;
unsigned codeIndex;
unsigned dataIndex;

52
mix/MixClient.cpp

@ -69,14 +69,14 @@ bytes MixBlockChain::createGenesisBlock(h256 _stateRoot)
MixClient::MixClient(std::string const& _dbPath):
m_dbPath(_dbPath)
{
resetState(std::map<Address, Account>());
resetState(std::unordered_map<Address, Account>());
}
MixClient::~MixClient()
{
}
void MixClient::resetState(std::map<Address, Account> const& _accounts, Secret const& _miner)
void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts, Secret const& _miner)
{
WriteGuard l(x_state);
Guard fl(x_filtersWatches);
@ -98,17 +98,20 @@ void MixClient::resetState(std::map<Address, Account> const& _accounts, Secret
m_executions.clear();
}
Transaction MixClient::replaceGas(Transaction const& _t, Secret const& _secret, u256 const& _gas)
Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas)
{
Transaction ret;
if (_t.isCreation())
return Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret);
ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce());
else
return Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret);
ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce());
ret.forceSender(_t.safeSender());
return ret;
}
void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret)
void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto)
{
Transaction t = _gasAuto ? replaceGas(_t, _secret, m_state.gasLimitRemaining()) : _t;
Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t;
bytes rlp = t.rlp();
// do debugging run first
@ -219,7 +222,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
// execute on a state
if (!_call)
{
t = _gasAuto ? replaceGas(_t, _secret, d.gasUsed) : _t;
t = _gasAuto ? replaceGas(_t, d.gasUsed) : _t;
er =_state.execute(lastHashes, t);
if (t.isCreation() && _state.code(d.contractAddress).empty())
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
@ -282,7 +285,7 @@ void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, by
WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
executeTransaction(t, m_state, false, _gasAuto, _secret);
executeTransaction(t, m_state, false, _gasAuto);
}
Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto)
@ -290,23 +293,23 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons
WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret));
eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
executeTransaction(t, m_state, false, _gasAuto, _secret);
executeTransaction(t, m_state, false, _gasAuto);
Address address = right160(sha3(rlpList(t.sender(), t.nonce())));
return address;
}
dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff)
dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff)
{
(void)_blockNumber;
Address a = toAddress(_secret);
State temp = asOf(eth::PendingBlock);
u256 n = temp.transactionsFrom(a);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
u256 n = temp.transactionsFrom(_from);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
bytes rlp = t.rlp();
WriteGuard lw(x_state); //TODO: lock is required only for last execution state
executeTransaction(t, temp, true, _gasAuto, _secret);
executeTransaction(t, temp, true, _gasAuto);
return lastExecution().result;
}
@ -320,28 +323,27 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons
return submitTransaction(_secret, _endowment, _init, _gas, _gasPrice, false);
}
dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
{
return call(_secret, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff);
return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff);
}
dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
{
(void)_blockNumber;
u256 n;
Address a = toAddress(_secret);
State temp;
{
ReadGuard lr(x_state);
temp = asOf(eth::PendingBlock);
n = temp.transactionsFrom(a);
n = temp.transactionsFrom(_from);
}
Transaction t(_value, _gasPrice, _gas, _data, n, _secret);
Transaction t(_value, _gasPrice, _gas, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
temp.addBalance(a, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
bytes rlp = t.rlp();
temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
WriteGuard lw(x_state); //TODO: lock is required only for last execution state
executeTransaction(t, temp, true, false, _secret);
executeTransaction(t, temp, true, false);
return lastExecution().result;
}

12
mix/MixClient.h

@ -48,19 +48,19 @@ public:
MixClient(std::string const& _dbPath);
virtual ~MixClient();
/// Reset state to the empty state with given balance.
void resetState(std::map<dev::Address, dev::eth::Account> const& _accounts, Secret const& _miner = Secret());
void resetState(std::unordered_map<dev::Address, dev::eth::Account> const& _accounts, Secret const& _miner = Secret());
void mine();
ExecutionResult lastExecution() const;
ExecutionResult execution(unsigned _index) const;
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;
dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) 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, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override;
dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override;
dev::eth::ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override;
void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto);
Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto);
dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict);
dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict);
void setAddress(Address _us) override;
void startMining() override;
@ -87,9 +87,9 @@ protected:
virtual void prepareForTransaction() override {}
private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret);
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto);
void noteChanged(h256Set const& _filters);
dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::Secret const& _secret, dev::u256 const& _gas);
dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas);
eth::State m_state;
eth::State m_startState;

17
test/CMakeLists.txt

@ -25,6 +25,11 @@ add_subdirectory(libethereum)
add_subdirectory(libevm)
add_subdirectory(libnatspec)
add_subdirectory(libp2p)
if (JSCONSOLE)
add_subdirectory(libjsengine)
endif()
if (SOLIDITY)
add_subdirectory(libsolidity)
endif ()
@ -41,6 +46,10 @@ include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
if (JSCONSOLE)
include_directories(${V8_INCLUDE_DIRS})
endif()
# search for test names and create ctest tests
enable_testing()
foreach(file ${SRC_LIST})
@ -65,14 +74,22 @@ target_link_libraries(testeth ${CURL_LIBRARIES})
target_link_libraries(testeth ethereum)
target_link_libraries(testeth ethcore)
target_link_libraries(testeth secp256k1)
if (JSCONSOLE)
target_link_libraries(testeth jsengine)
endif()
if (SOLIDITY)
target_link_libraries(testeth solidity)
endif ()
target_link_libraries(testeth testutils)
if (GUI AND NOT JUSTTESTS)
target_link_libraries(testeth webthree)
target_link_libraries(testeth natspec)
endif()
if (JSONRPC)
target_link_libraries(testeth web3jsonrpc)
target_link_libraries(testeth ${JSON_RPC_CPP_CLIENT_LIBRARIES})

2
test/TestHelper.cpp

@ -305,7 +305,7 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta
if (addressOptions.m_bHasStorage)
{
map<u256, u256> stateStorage = _statePost.storage(a.first);
unordered_map<u256, u256> stateStorage = _statePost.storage(a.first);
for (auto const& s: _stateExpect.storage(a.first))
CHECK(stateStorage[s.first] == s.second,
"Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(stateStorage[s.first]) << ", expected [" << s.first << "] = " << toHex(s.second));

2
test/fuzzTesting/checkRandomStateTest.cpp

@ -173,7 +173,7 @@ bool doStateTest(mValue& _v)
}
//checkStorage(importer.m_statePost.storage(expectedAddr), theState.storage(expectedAddr), expectedAddr);
map<u256, u256> _resultStore = theState.storage(expectedAddr);
unordered_map<u256, u256> _resultStore = theState.storage(expectedAddr);
for (auto&& expectedStorePair : importer.m_statePost.storage(expectedAddr))
{

1596
test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json

File diff suppressed because it is too large

323
test/libethereum/blockchain.cpp

@ -48,26 +48,35 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
{
for (auto& i: _v.get_obj())
{
cerr << i.first << endl;
mObject& o = i.second.get_obj();
if (test::Options::get().singleTest && test::Options::get().singleTestName != i.first)
{
o.clear();
continue;
}
cerr << i.first << endl;
BOOST_REQUIRE(o.count("genesisBlockHeader"));
BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj());
BOOST_REQUIRE(o.count("pre"));
ImportTest importer(o["pre"].get_obj());
TransientDirectory td_stateDB;
TransientDirectory td_stateDB_tmp;
State state(State::openDB(td_stateDB.path()), BaseState::Empty, biGenesisBlock.coinbaseAddress);
State stateTemp(State::openDB(td_stateDB_tmp.path()), BaseState::Empty, biGenesisBlock.coinbaseAddress);
importer.importState(o["pre"].get_obj(), state);
o["pre"] = fillJsonWithState(state);
state.commit();
State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress);
//Imported blocks from the start
typedef std::vector<bytes> uncleList;
typedef std::pair<bytes, uncleList> blockSet;
std::vector<blockSet> blockSets;
importer.importState(o["pre"].get_obj(), trueState);
o["pre"] = fillJsonWithState(trueState);
trueState.commit();
if (_fillin)
biGenesisBlock.stateRoot = state.rootHash();
biGenesisBlock.stateRoot = trueState.rootHash();
else
BOOST_CHECK_MESSAGE(biGenesisBlock.stateRoot == state.rootHash(), "root hash does not match");
BOOST_CHECK_MESSAGE(biGenesisBlock.stateRoot == trueState.rootHash(), "root hash does not match");
if (_fillin)
{
@ -83,20 +92,55 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
biGenesisBlock.verifyInternals(&rlpGenesisBlock.out());
o["genesisRLP"] = toHex(rlpGenesisBlock.out(), 2, HexPrefix::Add);
// construct blockchain
// construct true blockchain
TransientDirectory td;
BlockChain bc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill);
BlockChain trueBc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill);
if (_fillin)
{
BOOST_REQUIRE(o.count("blocks"));
mArray blArray;
blockSet genesis;
genesis.first = rlpGenesisBlock.out();
genesis.second = uncleList();
blockSets.push_back(genesis);
vector<BlockInfo> vBiBlocks;
vBiBlocks.push_back(biGenesisBlock);
size_t importBlockNumber = 0;
for (auto const& bl: o["blocks"].get_array())
{
stateTemp = state;
mObject blObj = bl.get_obj();
if (blObj.count("blocknumber") > 0)
importBlockNumber = std::max((int)toInt(blObj["blocknumber"]), 1);
else
importBlockNumber++;
//each time construct a new blockchain up to importBlockNumber (to generate next block header)
vBiBlocks.clear();
vBiBlocks.push_back(biGenesisBlock);
TransientDirectory td_stateDB, td_bc;
BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill);
State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress);
importer.importState(o["pre"].get_obj(), state);
state.commit();
for (size_t i = 1; i < importBlockNumber; i++) //0 block is genesis
{
BlockQueue uncleQueue;
uncleList uncles = blockSets.at(i).second;
for (size_t j = 0; j < uncles.size(); j++)
uncleQueue.import(&uncles.at(j), bc);
const bytes block = blockSets.at(i).first;
bc.sync(uncleQueue, state.db(), 4);
bc.attemptImport(block, state.db());
vBiBlocks.push_back(BlockInfo(block));
state.sync(bc);
}
// get txs
TransactionQueue txs;
@ -115,6 +159,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks);
BlockQueue uncleBlockQueue;
uncleList uncleBlockQueueList;
cnote << "import uncle in blockQueue";
for (size_t i = 0; i < vBiUncles.size(); i++)
{
@ -122,6 +167,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
try
{
uncleBlockQueue.import(&uncle.out(), bc);
uncleBlockQueueList.push_back(uncle.out());
}
catch(...)
{
@ -205,6 +251,25 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
bc.import(block2.out(), state.db());
state.sync(bc);
state.commit();
//there we get new blockchain status in state which could have more difficulty than we have in trueState
//attempt to import new block to the true blockchain
trueBc.sync(uncleBlockQueue, trueState.db(), 4);
trueBc.attemptImport(block2.out(), trueState.db());
trueState.sync(trueBc);
blockSet newBlock;
newBlock.first = block2.out();
newBlock.second = uncleBlockQueueList;
if (importBlockNumber < blockSets.size())
{
//make new correct history of imported blocks
blockSets[importBlockNumber] = newBlock;
for (size_t i = importBlockNumber + 1; i < blockSets.size(); i++)
blockSets.pop_back();
}
else
blockSets.push_back(newBlock);
}
// if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given
catch (...)
@ -213,7 +278,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
blObj.erase(blObj.find("blockHeader"));
blObj.erase(blObj.find("uncleHeaders"));
blObj.erase(blObj.find("transactions"));
state = stateTemp; //revert state as if it was before executing this block
}
blArray.push_back(blObj);
this_thread::sleep_for(chrono::seconds(1));
@ -224,14 +288,15 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
stateOptionsMap expectStateMap;
State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress);
importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap);
ImportTest::checkExpectedState(stateExpect, state, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow);
ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow);
o.erase(o.find("expect"));
}
o["blocks"] = blArray;
o["postState"] = fillJsonWithState(state);
o["postState"] = fillJsonWithState(trueState);
o["lastblockhash"] = toString(trueBc.info().hash());
//make all values hex
//make all values hex in pre section
State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress);
importer.importState(o["pre"].get_obj(), prestate);
o["pre"] = fillJsonWithState(prestate);
@ -241,14 +306,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
{
for (auto const& bl: o["blocks"].get_array())
{
bool importedAndBest = true;
mObject blObj = bl.get_obj();
bytes blockRLP;
try
{
state.sync(bc);
blockRLP = importByteArray(blObj["rlp"].get_str());
bc.import(blockRLP, state.db());
state.sync(bc);
trueState.sync(trueBc);
trueBc.import(blockRLP, trueState.db());
if (trueBc.info() != BlockInfo(blockRLP))
importedAndBest = false;
trueState.sync(trueBc);
}
// if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given
catch (Exception const& _e)
@ -284,124 +352,131 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader);
blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce);
BlockInfo blockFromRlp = bc.info();
//Check the fields restored from RLP to original fields
BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixHash == blockFromRlp.mixHash, "mixHash in given RLP not matching the block mixHash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!");
//Check transaction list
BlockInfo blockFromRlp = trueBc.info();
Transactions txsFromField;
for (auto const& txObj: blObj["transactions"].get_array())
if (importedAndBest)
{
mObject tx = txObj.get_obj();
BOOST_REQUIRE(tx.count("nonce"));
BOOST_REQUIRE(tx.count("gasPrice"));
BOOST_REQUIRE(tx.count("gasLimit"));
BOOST_REQUIRE(tx.count("to"));
BOOST_REQUIRE(tx.count("value"));
BOOST_REQUIRE(tx.count("v"));
BOOST_REQUIRE(tx.count("r"));
BOOST_REQUIRE(tx.count("s"));
BOOST_REQUIRE(tx.count("data"));
try
{
Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckTransaction::Everything);
txsFromField.push_back(t);
}
catch (Exception const& _e)
//Check the fields restored from RLP to original fields
BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixHash == blockFromRlp.mixHash, "mixHash in given RLP not matching the block mixHash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!");
//Check transaction list
Transactions txsFromField;
for (auto const& txObj: blObj["transactions"].get_array())
{
BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e));
mObject tx = txObj.get_obj();
BOOST_REQUIRE(tx.count("nonce"));
BOOST_REQUIRE(tx.count("gasPrice"));
BOOST_REQUIRE(tx.count("gasLimit"));
BOOST_REQUIRE(tx.count("to"));
BOOST_REQUIRE(tx.count("value"));
BOOST_REQUIRE(tx.count("v"));
BOOST_REQUIRE(tx.count("r"));
BOOST_REQUIRE(tx.count("s"));
BOOST_REQUIRE(tx.count("data"));
try
{
Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckTransaction::Everything);
txsFromField.push_back(t);
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e));
}
catch (exception const& _e)
{
cnote << _e.what();
}
}
catch (exception const& _e)
Transactions txsFromRlp;
RLP root(blockRLP);
for (auto const& tr: root[1])
{
cnote << _e.what();
Transaction tx(tr.data(), CheckTransaction::Everything);
txsFromRlp.push_back(tx);
}
}
Transactions txsFromRlp;
RLP root(blockRLP);
for (auto const& tr: root[1])
{
Transaction tx(tr.data(), CheckTransaction::Everything);
txsFromRlp.push_back(tx);
}
BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match");
BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match");
for (size_t i = 0; i < txsFromField.size(); ++i)
{
BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions from rlp and transaction from field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match");
}
for (size_t i = 0; i < txsFromField.size(); ++i)
{
BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions from rlp and transaction from field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match");
}
// check uncle list
// check uncle list
// uncles from uncle list field
vector<BlockInfo> uBlHsFromField;
if (blObj["uncleHeaders"].type() != json_spirit::null_type)
for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array())
{
mObject uBlH = uBlHeaderObj.get_obj();
BOOST_REQUIRE(uBlH.size() == 16);
bytes uncleRLP = createBlockRLPFromFields(uBlH);
const RLP c_uRLP(uncleRLP);
BlockInfo uncleBlockHeader;
try
{
uncleBlockHeader.populateFromHeader(c_uRLP);
}
catch(...)
// uncles from uncle list field
vector<BlockInfo> uBlHsFromField;
if (blObj["uncleHeaders"].type() != json_spirit::null_type)
for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array())
{
BOOST_ERROR("invalid uncle header");
mObject uBlH = uBlHeaderObj.get_obj();
BOOST_REQUIRE(uBlH.size() == 16);
bytes uncleRLP = createBlockRLPFromFields(uBlH);
const RLP c_uRLP(uncleRLP);
BlockInfo uncleBlockHeader;
try
{
uncleBlockHeader.populateFromHeader(c_uRLP);
}
catch(...)
{
BOOST_ERROR("invalid uncle header");
}
uBlHsFromField.push_back(uncleBlockHeader);
}
uBlHsFromField.push_back(uncleBlockHeader);
// uncles from block RLP
vector<BlockInfo> uBlHsFromRlp;
for (auto const& uRLP: root[2])
{
BlockInfo uBl;
uBl.populateFromHeader(uRLP);
uBlHsFromRlp.push_back(uBl);
}
// uncles from block RLP
vector<BlockInfo> uBlHsFromRlp;
for (auto const& uRLP: root[2])
{
BlockInfo uBl;
uBl.populateFromHeader(uRLP);
uBlHsFromRlp.push_back(uBl);
}
BOOST_REQUIRE_EQUAL(uBlHsFromField.size(), uBlHsFromRlp.size());
BOOST_REQUIRE_EQUAL(uBlHsFromField.size(), uBlHsFromRlp.size());
for (size_t i = 0; i < uBlHsFromField.size(); ++i)
BOOST_CHECK_MESSAGE(uBlHsFromField[i] == uBlHsFromRlp[i], "block header in rlp and in field do not match");
}//importedAndBest
}//all blocks
for (size_t i = 0; i < uBlHsFromField.size(); ++i)
BOOST_CHECK_MESSAGE(uBlHsFromField[i] == uBlHsFromRlp[i], "block header in rlp and in field do not match");
}
BOOST_REQUIRE(o.count("lastblockhash") > 0);
BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"].get_str(),
"Boost check: " + i.first + " lastblockhash does not match " + toString(trueBc.info().hash()) + " expected: " + o["lastblockhash"].get_str());
}
}
}
@ -443,6 +518,7 @@ mArray importUncles(mObject const& blObj, vector<BlockInfo>& vBiUncles, vector<B
// make uncle header valid
uncleBlockFromFields.timestamp = (u256)time(0);
cnote << "uncle block n = " << toString(uncleBlockFromFields.number);
if (vBiBlocks.size() > 2)
{
if (uncleBlockFromFields.number - 1 < vBiBlocks.size())
@ -669,6 +745,11 @@ BOOST_AUTO_TEST_CASE(bcForkBlockTest)
dev::test::executeTests("bcForkBlockTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests);
}
BOOST_AUTO_TEST_CASE(bcTotalDifficultyTest)
{
dev::test::executeTests("bcTotalDifficultyTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests);
}
BOOST_AUTO_TEST_CASE(bcInvalidRLPTest)
{
dev::test::executeTests("bcInvalidRLPTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests);

2
test/libethereum/state.cpp

@ -99,7 +99,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
ImportTest::checkExpectedState(importer.m_statePost, theState);
auto expectedAddrs = importer.m_statePost.addresses();
auto resultAddrs = theState.addresses();
checkAddresses<map<Address, u256> >(expectedAddrs, resultAddrs);
checkAddresses(expectedAddrs, resultAddrs);
#endif
BOOST_CHECK_MESSAGE(theState.rootHash() == h256(o["postStateRoot"].get_str()), "wrong post state root");
}

5
test/libjsengine/CMakeLists.txt

@ -0,0 +1,5 @@
cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRCS)
add_sources(${SRCS})

71
test/libjsengine/JSV8Engine.cpp

@ -0,0 +1,71 @@
//
// Created by Marek Kotewicz on 27/04/15.
//
#include <boost/test/unit_test.hpp>
#include <libjsengine/JSV8Engine.h>
#include <libjsengine/JSV8Printer.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
BOOST_AUTO_TEST_SUITE(jsv8engine)
BOOST_AUTO_TEST_CASE(evalInteger)
{
JSV8Engine engine;
JSV8Printer printer(engine);
auto value = engine.eval("1 + 1");
string result = printer.print(value).cstr();
BOOST_CHECK_EQUAL(result, "2");
}
BOOST_AUTO_TEST_CASE(evalString)
{
JSV8Engine engine;
JSV8Printer printer(engine);
auto value = engine.eval("'hello ' + 'world'");
string result = printer.print(value).cstr();
BOOST_CHECK_EQUAL(result, "hello world");
}
BOOST_AUTO_TEST_CASE(evalEmpty)
{
JSV8Engine engine;
JSV8Printer printer(engine);
auto value = engine.eval("");
string result = printer.print(value).cstr();
BOOST_CHECK_EQUAL(result, "undefined");
}
BOOST_AUTO_TEST_CASE(evalAssignment)
{
JSV8Engine engine;
JSV8Printer printer(engine);
auto value = engine.eval("x = 5");
string result = printer.print(value).cstr();
BOOST_CHECK_EQUAL(result, "5");
}
BOOST_AUTO_TEST_CASE(evalIncorrectExpression)
{
JSV8Engine engine;
JSV8Printer printer(engine);
auto value = engine.eval("[");
string result = printer.print(value).cstr();
BOOST_CHECK_EQUAL(result, "Error: Uncaught SyntaxError: Unexpected end of input");
}
BOOST_AUTO_TEST_CASE(evalNull)
{
JSV8Engine engine;
JSV8Printer printer(engine);
auto value = engine.eval("null");
string result = printer.print(value).cstr();
string prettyResult = printer.prettyPrint(value).cstr();
BOOST_CHECK_EQUAL(result, "null");
BOOST_CHECK_EQUAL(prettyResult.find("null") != std::string::npos, true);
}
BOOST_AUTO_TEST_SUITE_END()
Loading…
Cancel
Save