Browse Source

Merge remote-tracking branch 'ethereum/develop' into sol_overloadingFunctions

cl-refactor
chriseth 10 years ago
parent
commit
f2f744006c
  1. 2
      .gitignore
  2. 262
      CMakeLists.txt
  3. 2
      CodingStandards.txt
  4. 2
      README.md
  5. 16
      abi/CMakeLists.txt
  6. 769
      abi/main.cpp
  7. 6
      alethzero/CMakeLists.txt
  8. 64
      alethzero/Connect.cpp
  9. 55
      alethzero/Connect.h
  10. 126
      alethzero/Connect.ui
  11. 139
      alethzero/DappHost.cpp
  12. 58
      alethzero/DappHost.h
  13. 218
      alethzero/DappLoader.cpp
  14. 94
      alethzero/DappLoader.h
  15. 3
      alethzero/Debugger.cpp
  16. 83
      alethzero/Main.ui
  17. 451
      alethzero/MainWin.cpp
  18. 17
      alethzero/MainWin.h
  19. 395
      alethzero/Transact.cpp
  20. 16
      alethzero/Transact.h
  21. 28
      alethzero/WebPage.cpp
  22. 40
      alethzero/WebPage.h
  23. 31
      cmake/EthCompilerSettings.cmake
  24. 60
      cmake/EthDependencies.cmake
  25. 40
      cmake/EthUtils.cmake
  26. 29
      cmake/Findjson_rpc_cpp.cmake
  27. 15
      cmake/scripts/runtest.cmake
  28. 117
      eth/main.cpp
  29. 35
      ethrpctest/CMakeLists.txt
  30. 129
      ethrpctest/CommandLineInterface.cpp
  31. 46
      ethrpctest/CommandLineInterface.h
  32. 34
      ethrpctest/main.cpp
  33. 4
      evmjit/CMakeLists.txt
  34. 3
      evmjit/libevmjit-cpp/CMakeLists.txt
  35. 39
      evmjit/libevmjit-cpp/Env.cpp
  36. 4
      evmjit/libevmjit-cpp/JitVM.cpp
  37. 135
      evmjit/libevmjit/Arith256.cpp
  38. 320
      evmjit/libevmjit/Array.cpp
  39. 74
      evmjit/libevmjit/Array.h
  40. 66
      evmjit/libevmjit/BasicBlock.cpp
  41. 4
      evmjit/libevmjit/BasicBlock.h
  42. 1
      evmjit/libevmjit/BuildInfo.h.in
  43. 35
      evmjit/libevmjit/CMakeLists.txt
  44. 112
      evmjit/libevmjit/Cache.cpp
  45. 24
      evmjit/libevmjit/Cache.h
  46. 10
      evmjit/libevmjit/Common.h
  47. 78
      evmjit/libevmjit/Compiler.cpp
  48. 4
      evmjit/libevmjit/Compiler.h
  49. 9
      evmjit/libevmjit/Endianness.cpp
  50. 1
      evmjit/libevmjit/ExecStats.cpp
  51. 1
      evmjit/libevmjit/ExecStats.h
  52. 117
      evmjit/libevmjit/ExecutionEngine.cpp
  53. 7
      evmjit/libevmjit/ExecutionEngine.h
  54. 10
      evmjit/libevmjit/Ext.cpp
  55. 2
      evmjit/libevmjit/Ext.h
  56. 230
      evmjit/libevmjit/GasMeter.cpp
  57. 4
      evmjit/libevmjit/GasMeter.h
  58. 158
      evmjit/libevmjit/Memory.cpp
  59. 6
      evmjit/libevmjit/Memory.h
  60. 29
      evmjit/libevmjit/Optimizer.cpp
  61. 19
      evmjit/libevmjit/Optimizer.h
  62. 25
      evmjit/libevmjit/Runtime.cpp
  63. 24
      evmjit/libevmjit/Runtime.h
  64. 87
      evmjit/libevmjit/RuntimeManager.cpp
  65. 25
      evmjit/libevmjit/RuntimeManager.h
  66. 138
      evmjit/libevmjit/Stack.cpp
  67. 15
      evmjit/libevmjit/Stack.h
  68. 6
      evmjit/libevmjit/Type.cpp
  69. 3
      evmjit/libevmjit/Type.h
  70. 22
      evmjit/libevmjit/Utils.cpp
  71. 36
      evmjit/libevmjit/Utils.h
  72. 5
      evmjit/libevmjit/interface.cpp
  73. 111
      libdevcore/Assertions.h
  74. 2
      libdevcore/Common.cpp
  75. 47
      libdevcore/Common.h
  76. 8
      libdevcore/CommonData.cpp
  77. 20
      libdevcore/CommonData.h
  78. 2
      libdevcore/CommonIO.cpp
  79. 22
      libdevcore/CommonIO.h
  80. 18
      libdevcore/CommonJS.cpp
  81. 41
      libdevcore/CommonJS.h
  82. 4
      libdevcore/Exceptions.h
  83. 17
      libdevcore/FixedHash.h
  84. 31
      libdevcore/RLP.cpp
  85. 34
      libdevcore/RLP.h
  86. 38
      libdevcore/StructuredLogger.cpp
  87. 13
      libdevcore/StructuredLogger.h
  88. 5
      libdevcore/vector_ref.h
  89. 66
      libdevcrypto/Common.cpp
  90. 21
      libdevcrypto/Common.h
  91. 125
      libdevcrypto/CryptoPP.cpp
  92. 14
      libdevcrypto/CryptoPP.h
  93. 7
      libdevcrypto/ECDHE.cpp
  94. 17
      libdevcrypto/ECDHE.h
  95. 9
      libdevcrypto/FileSystem.cpp
  96. 2
      libdevcrypto/FileSystem.h
  97. 2
      libdevcrypto/MemoryDB.h
  98. 8
      libethash/CMakeLists.txt
  99. 967
      libethash/data_sizes.h
  100. 136
      libethash/ethash.h

2
.gitignore

@ -64,6 +64,8 @@ profile
DerivedData
project.pbxproj
# JetBrains stuff
.idea/
doc/html
*.autosave

262
CMakeLists.txt

@ -14,35 +14,39 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# user defined, defaults
# Normally, set(...CACHE...) creates cache variables, but does not modify them.
function(createDefaultCacheConfig)
set(HEADLESS OFF CACHE BOOL "Do not compile GUI (AlethZero)")
set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)")
set(PARANOIA OFF CACHE BOOL "Additional run-time checks")
set(JSONRPC ON CACHE BOOL "Build with jsonprc. default on")
set(EVMJIT OFF CACHE BOOL "Build a just-in-time compiler for EVM code (requires LLVM)")
set(FATDB OFF CACHE BOOL "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents.")
set(JUSTTESTS OFF CACHE BOOL "Build only for tests.")
set(SOLIDITY ON CACHE BOOL "Build the Solidity language components (requried unless HEADLESS)")
set(USENPM OFF CACHE BOOL "Use npm to recompile ethereum.js if it was changed")
set(PROFILING OFF CACHE BOOL "Build in support for profiling")
set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).")
set(SOLIDITY ON CACHE BOOL "Build the Solidity language components")
set(SERPENT ON CACHE BOOL "Build the Serpent language components")
set(TOOLS ON CACHE BOOL "Build the tools components")
set(NCURSES ON CACHE BOOL "Build the NCurses components")
set(GUI ON CACHE BOOL "Build GUI components (AlethZero, Mix)")
set(TESTS ON CACHE BOOL "Build the tests.")
set(EVMJIT OFF CACHE BOOL "Build just-in-time compiler for EVM code (requires LLVM)")
set(ETHASHCL OFF CACHE BOOL "Build in support for GPU mining via OpenCL")
endfunction()
# propagates CMake configuration options to the compiler
function(configureProject)
if (PARANOIA)
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_definitions(-DETH_PARANOIA)
else ()
message(FATAL_ERROR "Paranoia requires debug.")
endif ()
add_definitions(-DETH_PARANOIA)
endif ()
if (VMTRACE)
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_definitions(-DETH_VMTRACE)
else ()
message(FATAL_ERROR "VM tracing requires debug.")
endif ()
add_definitions(-DETH_VMTRACE)
endif ()
if (ETHASHCL)
add_definitions(-DETH_ETHASHCL)
endif()
if (EVMJIT)
add_definitions(-DETH_EVMJIT)
endif()
@ -55,8 +59,8 @@ function(configureProject)
add_definitions(-DETH_SOLIDITY)
endif()
if (HEADLESS OR JUSTTESTS)
add_definitions(-DETH_HEADLESS)
if (GUI)
add_definitions(-DETH_GUI)
endif()
endfunction()
@ -117,6 +121,17 @@ endfunction()
set(CMAKE_AUTOMOC ON)
cmake_policy(SET CMP0015 NEW)
# Clear invalid option
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
if (PARANOIA)
message("Paranoia requires debug - disabling for release build.")
set(PARANOIA OFF)
endif ()
if (VMTRACE)
message("VM Tracing requires debug - disabling for release build.")
set (VMTRACE OFF)
endif ()
endif ()
createDefaultCacheConfig()
configureProject()
@ -124,9 +139,133 @@ configureProject()
# Force chromium.
set (ETH_HAVE_WEBENGINE 1)
message(STATUS "CMAKE_VERSION: ${CMAKE_VERSION}")
message("-- VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}; JSONRPC: ${JSONRPC}; EVMJIT: ${EVMJIT}; FATDB: ${FATDB}; CHROMIUM: ${ETH_HAVE_WEBENGINE}")
# Normalise build options
# TODO: Abstract into something sensible and move into a function.
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(DECENT_PLATFORM OFF)
else ()
set(DECENT_PLATFORM ON)
endif ()
# Backwards compatibility
if (HEADLESS)
set(BUNDLE "minimal")
endif ()
if (PARANOIA)
set(PARANOIA ON)
else ()
set(PARANOIA OFF)
endif ()
if (VMTRACE)
set(VMTRACE ON)
else ()
set(VMTRACE OFF)
endif ()
if (EVMJIT)
set(EVMJIT ON)
else ()
set(EVMJIT OFF)
endif()
if (FATDB)
set(FATDB ON)
else ()
set(FATDB OFF)
endif()
if (JSONRPC)
set(JSONRPC ON)
else ()
set(JSONRPC OFF)
endif ()
if (USENPM)
set(USENPM ON)
else ()
set(USENPM OFF)
endif ()
if (PROFILING)
set(PROFILING ON)
else ()
set(PROFILING OFF)
endif ()
if (SOLIDITY)
set(SOLIDITY ON)
else ()
set(SOLIDITY OFF)
endif()
if (SERPENT)
set(SERPENT ${DECENT_PLATFORM})
else ()
set(SERPENT OFF)
endif()
if (GUI)
set(GUI ON)
set(JSONRPC ON)
else ()
set(GUI OFF)
endif ()
if (TESTS)
set(TESTS ON)
else ()
set(TESTS OFF)
endif ()
if (TOOLS)
set(TOOLS ON)
else ()
set(TOOLS OFF)
endif ()
if (ETHASHCL)
set(ETHASHCL ON)
else ()
set(ETHASHCL OFF)
endif()
if (NCURSES)
set(NCURSES ${DECENT_PLATFORM})
else ()
set(NCURSES OFF)
endif ()
if (BUNDLE STREQUAL "minimal")
set(SERPENT OFF)
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS ON)
set(TESTS OFF)
elseif (BUNDLE STREQUAL "full")
set(SERPENT ${DECENT_PLATFORM})
set(SOLIDITY ON)
set(USENPM ON)
set(GUI ON)
set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON)
set(TESTS ON)
set(FATDB ON)
elseif (BUNDLE STREQUAL "tests")
set(SERPENT ${DECENT_PLATFORM})
set(SOLIDITY ON)
set(USENPM OFF)
set(GUI OFF)
set(NCURSES OFF)
set(TOOLS OFF)
set(TESTS ON)
set(FATDB ON)
elseif (BUNDLE STREQUAL "user")
set(SERPENT OFF)
set(SOLIDITY OFF)
set(USENPM OFF)
set(GUI ON)
set(NCURSES ${DECENT_PLATFORM})
set(TOOLS ON)
set(TESTS OFF)
endif ()
# Default CMAKE_BUILD_TYPE to "Release".
set(CMAKE_BUILD_TYPE CACHE STRING "Release")
if ("x${CMAKE_BUILD_TYPE}" STREQUAL "x")
set(CMAKE_BUILD_TYPE "Release")
endif ()
# Default TARGET_PLATFORM to "linux".
set(TARGET_PLATFORM CACHE STRING "linux")
@ -134,6 +273,32 @@ if ("x${TARGET_PLATFORM}" STREQUAL "x")
set(TARGET_PLATFORM "linux")
endif ()
message("------------------------------------------------------------------------")
message("-- CMake Version ${CMAKE_VERSION}")
message("-- CMAKE_BUILD_TYPE Build type ${CMAKE_BUILD_TYPE}")
message("-- TARGET_PLATFORM Target platform ${TARGET_PLATFORM}")
message("-- BUNDLE Build bundle ${BUNDLE}")
message("--------------------------------------------------------------- features")
message("-- Chromium support ${ETH_HAVE_WEBENGINE}")
message("-- VMTRACE VM execution tracing ${VMTRACE}")
message("-- PROFILING Profiling support ${PROFILING}")
message("-- PARANOIA Additional (SLOW) database checking ${PARANOIA}")
message("-- FATDB Full database exploring ${FATDB}")
message("-- JSONRPC JSON-RPC support ${JSONRPC}")
message("-- USENPM Javascript source building ${USENPM}")
message("------------------------------------------------------------- components")
message("-- TOOLS Build basic tools ${TOOLS}")
message("-- SOLIDITY Build Solidity language components ${SOLIDITY}")
message("-- SERPENT Build Serpent language components ${SERPENT}")
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("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}")
message("------------------------------------------------------------------------")
message("")
if ("${TARGET_PLATFORM}" STREQUAL "linux")
set(CMAKE_THREAD_LIBS_INIT pthread)
endif ()
@ -154,20 +319,23 @@ if (EVMJIT)
endif()
add_subdirectory(libdevcore)
add_subdirectory(rlp)
add_subdirectory(libevmcore)
add_subdirectory(liblll)
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
if (SERPENT)
add_subdirectory(libserpent)
add_subdirectory(sc)
endif ()
add_subdirectory(libsolidity)
if (SOLIDITY)
add_subdirectory(libsolidity)
endif ()
if (NOT JUSTTESTS)
if (TOOLS)
add_subdirectory(lllc)
add_subdirectory(solc)
if (SOLIDITY)
add_subdirectory(solc)
endif ()
endif()
if (JSONRPC)
@ -180,44 +348,54 @@ add_subdirectory(libdevcrypto)
add_subdirectory(libwhisper)
add_subdirectory(libethash)
if (ETHASHCL)
add_subdirectory(libethash-cl)
endif ()
add_subdirectory(libethcore)
add_subdirectory(libevm)
add_subdirectory(libethereum)
add_subdirectory(libwebthree)
add_subdirectory(test)
if (NOT JUSTTESTS)
if (TESTS)
add_subdirectory(libtestutils)
add_subdirectory(test)
if (JSONRPC)
add_subdirectory(ethrpctest)
endif ()
endif ()
if (TOOLS)
add_subdirectory(rlp)
add_subdirectory(abi)
add_subdirectory(eth)
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
add_subdirectory(exp)
endif ()
# TODO check msvc
if(NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
add_subdirectory(neth)
endif ()
endif()
if (NOT HEADLESS)
if (NCURSES)
add_subdirectory(neth)
endif ()
add_subdirectory(libnatspec)
add_subdirectory(libjsqrc)
if (GUI)
if (ETH_HAVE_WEBENGINE)
add_subdirectory(alethzero)
# add_subdirectory(third) // reenable once not qtwebkit.
endif()
add_subdirectory(mix)
add_subdirectory(libnatspec)
add_subdirectory(libjsqrc)
if (ETH_HAVE_WEBENGINE)
add_subdirectory(alethzero)
# add_subdirectory(third) // reenable once not qtwebkit.
endif()
endif()
if (SOLIDITY)
add_subdirectory(mix)
endif ()
enable_testing()
add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth)
endif()
#unset(TARGET_PLATFORM CACHE)

2
CodingStandards.txt

@ -13,7 +13,7 @@ c. Don't use braces for condition-body one-liners.
d. Never place condition bodies on same line as condition.
e. Space between first paren and keyword, but *not* following first paren or preceeding final paren.
f. No spaces when fewer than intra-expression three parens together; when three or more, space according to clarity.
g. No spaces for subscripting.
g. No spaces for subscripting or unary operators.
h. No space before ':' but one after it, except in the ternary operator: one on both sides.
i. Space all other operators.
j. Braces, when used, always have their own lines and are at same indentation level as "parent" scope.

2
README.md

@ -1,5 +1,7 @@
## Ethereum C++ Client.
[![Join the chat at https://gitter.im/ethereum/cpp-ethereum](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/cpp-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
By Gav Wood et al, 2013, 2014, 2015.
| Linux | OSX | Windows

16
abi/CMakeLists.txt

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

769
abi/main.cpp

@ -0,0 +1,769 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file main.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* RLP tool.
*/
#include <fstream>
#include <iostream>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include "../test/JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h>
#include <libethereum/Client.h>
using namespace std;
using namespace dev;
namespace js = json_spirit;
void help()
{
cout
<< "Usage abi enc <method_name> (<arg1>, (<arg2>, ... ))" << endl
<< " abi enc -a <abi.json> <method_name> (<arg1>, (<arg2>, ... ))" << endl
<< " abi dec -a <abi.json> [ <signature> | <unique_method_name> ]" << endl
<< "Options:" << endl
<< " -a,--abi-file <filename> Specify the JSON ABI file." << endl
<< " -h,--help Print this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl
<< "Input options:" << endl
<< " -f,--format-prefix Require all input formats to be prefixed e.g. 0x for hex, . for decimal, @ for binary." << endl
<< " -F,--no-format-prefix Require no input format to be prefixed." << endl
<< " -t,--typing Require all arguments to be typed e.g. b32: (bytes32), u64: (uint64), b[]: (byte[]), i: (int256)." << endl
<< " -T,--no-typing Require no arguments to be typed." << endl
<< "Output options:" << endl
<< " -i,--index <n> Output only the nth (counting from 0) return value." << endl
<< " -d,--decimal All data should be displayed as decimal." << endl
<< " -x,--hex Display all data as hex." << endl
<< " -b,--binary Display all data as binary." << endl
<< " -p,--prefix Prefix by a base identifier." << endl
;
exit(0);
}
void version()
{
cout << "abi version " << dev::Version << endl;
exit(0);
}
enum class Mode
{
Encode,
Decode
};
enum class Encoding
{
Auto,
Decimal,
Hex,
Binary,
};
enum class Tristate
{
False = false,
True = true,
Mu
};
enum class Format
{
Binary,
Hex,
Decimal,
Open,
Close
};
struct InvalidUserString: public Exception {};
struct InvalidFormat: public Exception {};
enum class Base
{
Unknown,
Bytes,
Address,
Int,
Uint,
Fixed
};
static const map<Base, string> s_bases =
{
{ Base::Bytes, "bytes" },
{ Base::Address, "address" },
{ Base::Int, "int" },
{ Base::Uint, "uint" },
{ Base::Fixed, "fixed" }
};
struct EncodingPrefs
{
Encoding e = Encoding::Auto;
bool prefix = true;
};
struct ABIType
{
Base base = Base::Unknown;
unsigned size = 32;
unsigned ssize = 0;
vector<int> dims;
string name;
ABIType() = default;
ABIType(std::string const& _type, std::string const& _name):
name(_name)
{
string rest;
for (auto const& i: s_bases)
if (boost::algorithm::starts_with(_type, i.second))
{
base = i.first;
rest = _type.substr(i.second.size());
}
if (base == Base::Unknown)
throw InvalidFormat();
boost::regex r("(\\d*)(x(\\d+))?((\\[\\d*\\])*)");
boost::smatch res;
boost::regex_match(rest, res, r);
size = res[1].length() > 0 ? stoi(res[1]) : 0;
ssize = res[3].length() > 0 ? stoi(res[3]) : 0;
boost::regex r2("\\[(\\d*)\\](.*)");
for (rest = res[4]; boost::regex_match(rest, res, r2); rest = res[2])
dims.push_back(!res[1].length() ? -1 : stoi(res[1]));
}
ABIType(std::string const& _s)
{
if (_s.size() < 1)
return;
switch (_s[0])
{
case 'b': base = Base::Bytes; break;
case 'a': base = Base::Address; break;
case 'i': base = Base::Int; break;
case 'u': base = Base::Uint; break;
case 'f': base = Base::Fixed; break;
default: throw InvalidFormat();
}
if (_s.size() < 2)
{
if (base == Base::Fixed)
size = ssize = 16;
else if (base == Base::Address || base == Base::Bytes)
size = 0;
else
size = 32;
return;
}
strings d;
boost::algorithm::split(d, _s, boost::is_any_of("*"));
string s = d[0];
if (s.find_first_of('x') == string::npos)
size = stoi(s.substr(1));
else
{
size = stoi(s.substr(1, s.find_first_of('x') - 1));
ssize = stoi(s.substr(s.find_first_of('x') + 1));
}
for (unsigned i = 1; i < d.size(); ++i)
if (d[i].empty())
dims.push_back(-1);
else
dims.push_back(stoi(d[i]));
}
string canon() const
{
string ret;
switch (base)
{
case Base::Bytes: ret = "bytes" + (size > 0 ? toString(size) : ""); break;
case Base::Address: ret = "address"; break;
case Base::Int: ret = "int" + toString(size); break;
case Base::Uint: ret = "uint" + toString(size); break;
case Base::Fixed: ret = "fixed" + toString(size) + "x" + toString(ssize); break;
default: throw InvalidFormat();
}
for (int i: dims)
ret += "[" + ((i > -1) ? toString(i) : "") + "]";
return ret;
}
bool isBytes() const { return base == Base::Bytes && !size; }
string render(bytes const& _data, EncodingPrefs _e) const
{
if (base == Base::Uint || base == Base::Int)
{
if (_e.e == Encoding::Hex)
return (_e.prefix ? "0x" : "") + toHex(toCompactBigEndian(fromBigEndian<bigint>(bytesConstRef(&_data).cropped(32 - size / 8))));
else
{
bigint i = fromBigEndian<bigint>(bytesConstRef(&_data).cropped(32 - size / 8));
if (base == Base::Int && i > (bigint(1) << (size - 1)))
i -= (bigint(1) << size);
return toString(i);
}
}
else if (base == Base::Address)
{
Address a = Address(h256(_data), Address::AlignRight);
return _e.e == Encoding::Binary ? asString(a.asBytes()) : ((_e.prefix ? "0x" : "") + toString(a));
}
else if (isBytes())
{
return _e.e == Encoding::Binary ? asString(_data) : ((_e.prefix ? "0x" : "") + toHex(_data));
}
else if (base == Base::Bytes)
{
bytesConstRef b(&_data);
b = b.cropped(0, size);
return _e.e == Encoding::Binary ? asString(b) : ((_e.prefix ? "0x" : "") + toHex(b));
}
else
throw InvalidFormat();
}
bytes unrender(bytes const& _data, Format _f) const
{
if (isBytes())
{
auto ret = _data;
while (ret.size() % 32 != 0)
ret.push_back(0);
return ret;
}
else
return aligned(_data, _f, 32);
}
void noteHexInput(unsigned _nibbles) { if (base == Base::Unknown) { if (_nibbles == 40) base = Base::Address; else { base = Base::Bytes; size = _nibbles / 2; } } }
void noteBinaryInput() { if (base == Base::Unknown) { base = Base::Bytes; size = 32; } }
void noteDecimalInput() { if (base == Base::Unknown) { base = Base::Uint; size = 32; } }
bytes aligned(bytes const& _b, Format _f, unsigned _length) const
{
bytes ret = _b;
while (ret.size() < _length)
if (base == Base::Bytes || (base == Base::Unknown && _f == Format::Binary))
ret.push_back(0);
else
ret.insert(ret.begin(), 0);
while (ret.size() > _length)
if (base == Base::Bytes || (base == Base::Unknown && _f == Format::Binary))
ret.pop_back();
else
ret.erase(ret.begin());
return ret;
}
};
tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix, Tristate _typing)
{
ABIType type;
string val;
if (_typing == Tristate::True || (_typing == Tristate::Mu && _arg.find(':') != string::npos))
{
if (_arg.find(':') == string::npos)
throw InvalidUserString();
type = ABIType(_arg.substr(0, _arg.find(':')));
val = _arg.substr(_arg.find(':') + 1);
}
else
val = _arg;
if (_prefix != Tristate::False)
{
if (val.substr(0, 2) == "0x")
{
type.noteHexInput(val.size() - 2);
return make_tuple(fromHex(val), type, Format::Hex);
}
if (val.substr(0, 1) == "+")
{
type.noteDecimalInput();
return make_tuple(toCompactBigEndian(bigint(val.substr(1))), type, Format::Decimal);
}
if (val.substr(0, 1) == "'")
{
type.noteBinaryInput();
return make_tuple(asBytes(val.substr(1)), type, Format::Binary);
}
if (val == "[")
return make_tuple(bytes(), type, Format::Open);
if (val == "]")
return make_tuple(bytes(), type, Format::Close);
}
if (_prefix != Tristate::True)
{
if (val.find_first_not_of("0123456789") == string::npos)
{
type.noteDecimalInput();
return make_tuple(toCompactBigEndian(bigint(val)), type, Format::Decimal);
}
if (val.find_first_not_of("0123456789abcdefABCDEF") == string::npos)
{
type.noteHexInput(val.size());
return make_tuple(fromHex(val), type, Format::Hex);
}
if (val == "[")
return make_tuple(bytes(), type, Format::Open);
if (val == "]")
return make_tuple(bytes(), type, Format::Close);
type.noteBinaryInput();
return make_tuple(asBytes(val), type, Format::Binary);
}
throw InvalidUserString();
}
struct ExpectedAdditionalParameter: public Exception {};
struct ExpectedOpen: public Exception {};
struct ExpectedClose: public Exception {};
struct ABIMethod
{
string name;
vector<ABIType> ins;
vector<ABIType> outs;
bool isConstant = false;
// isolation *IS* documentation.
ABIMethod() = default;
ABIMethod(js::mObject _o)
{
name = _o["name"].get_str();
isConstant = _o["constant"].get_bool();
if (_o.count("inputs"))
for (auto const& i: _o["inputs"].get_array())
{
js::mObject a = i.get_obj();
ins.push_back(ABIType(a["type"].get_str(), a["name"].get_str()));
}
if (_o.count("outputs"))
for (auto const& i: _o["outputs"].get_array())
{
js::mObject a = i.get_obj();
outs.push_back(ABIType(a["type"].get_str(), a["name"].get_str()));
}
}
ABIMethod(string const& _name, vector<ABIType> const& _args)
{
name = _name;
ins = _args;
}
string sig() const
{
string methodArgs;
for (auto const& arg: ins)
methodArgs += (methodArgs.empty() ? "" : ",") + arg.canon();
return name + "(" + methodArgs + ")";
}
FixedHash<4> id() const { return FixedHash<4>(sha3(sig())); }
std::string solidityDeclaration() const
{
ostringstream ss;
ss << "function " << name << "(";
int f = 0;
for (ABIType const& i: ins)
ss << (f++ ? ", " : "") << i.canon() << " " << i.name;
ss << ") ";
if (isConstant)
ss << "constant ";
if (!outs.empty())
{
ss << "returns(";
f = 0;
for (ABIType const& i: outs)
ss << (f++ ? ", " : "") << i.canon() << " " << i.name;
ss << ")";
}
return ss.str();
}
bytes encode(vector<pair<bytes, Format>> const& _params) const
{
bytes ret = name.empty() ? bytes() : id().asBytes();
bytes suffix;
// int int[] int
// example: 42 [ 1 2 3 ] 69
// int[2][][3]
// example: [ [ [ 1 2 3 ] [ 4 5 6 ] ] [ ] ]
unsigned pi = 0;
for (ABIType const& a: ins)
{
if (pi >= _params.size())
throw ExpectedAdditionalParameter();
auto put = [&]() {
if (a.isBytes())
ret += h256(u256(_params[pi].first.size())).asBytes();
suffix += a.unrender(_params[pi].first, _params[pi].second);
pi++;
if (pi >= _params.size())
throw ExpectedAdditionalParameter();
};
function<void(vector<int>, unsigned)> putDim = [&](vector<int> addr, unsigned q) {
if (addr.size() == a.dims.size())
put();
else
{
if (_params[pi].second != Format::Open)
throw ExpectedOpen();
++pi;
int l = a.dims[a.dims.size() - 1 - addr.size()];
if (l == -1)
{
// read ahead in params and discover the arity.
unsigned depth = 0;
l = 0;
for (unsigned pi2 = pi; depth || _params[pi2].second != Format::Close;)
{
if (_params[pi2].second == Format::Open)
++depth;
if (_params[pi2].second == Format::Close)
--depth;
if (!depth)
++l;
if (++pi2 == _params.size())
throw ExpectedClose();
}
ret += h256(u256(l)).asBytes();
}
q *= l;
for (addr.push_back(0); addr.back() < l; ++addr.back())
putDim(addr, q);
if (_params[pi].second != Format::Close)
throw ExpectedClose();
++pi;
}
};
putDim(vector<int>(), 1);
}
return ret + suffix;
}
string decode(bytes const& _data, int _index, EncodingPrefs _ep)
{
stringstream out;
unsigned di = 0;
vector<unsigned> catDims;
for (ABIType const& a: outs)
{
auto put = [&]() {
if (a.isBytes())
{
catDims.push_back(fromBigEndian<unsigned>(bytesConstRef(&_data).cropped(di, 32)));
di += 32;
}
};
function<void(vector<int>, unsigned)> putDim = [&](vector<int> addr, unsigned q) {
if (addr.size() == a.dims.size())
put();
else
{
int l = a.dims[a.dims.size() - 1 - addr.size()];
if (l == -1)
{
l = fromBigEndian<unsigned>(bytesConstRef(&_data).cropped(di, 32));
catDims.push_back(l);
di += 32;
}
q *= l;
for (addr.push_back(0); addr.back() < l; ++addr.back())
putDim(addr, q);
}
};
putDim(vector<int>(), 1);
}
unsigned d = 0;
for (ABIType const& a: outs)
{
if (_index == -1 && out.tellp() > 0)
out << ", ";
auto put = [&]() {
if (a.isBytes())
{
out << a.render(bytesConstRef(&_data).cropped(di, catDims[d]).toBytes(), _ep);
di += ((catDims[d] + 31) / 32) * 32;
d++;
}
else
{
out << a.render(bytesConstRef(&_data).cropped(di, 32).toBytes(), _ep);
di += 32;
}
};
function<void(vector<int>)> putDim = [&](vector<int> addr) {
if (addr.size() == a.dims.size())
put();
else
{
out << "[";
addr.push_back(0);
int l = a.dims[a.dims.size() - 1 - (addr.size() - 1)];
if (l == -1)
l = catDims[d++];
for (addr.back() = 0; addr.back() < l; ++addr.back())
{
if (addr.back())
out << ", ";
putDim(addr);
}
out << "]";
}
};
putDim(vector<int>());
}
return out.str();
}
};
string canonSig(string const& _name, vector<ABIType> const& _args)
{
try {
string methodArgs;
for (auto const& arg: _args)
methodArgs += (methodArgs.empty() ? "" : ",") + arg.canon();
return _name + "(" + methodArgs + ")";
}
catch (...) {
return string();
}
}
struct UnknownMethod: public Exception {};
struct OverloadedMethod: public Exception {};
class ABI
{
public:
ABI() = default;
ABI(std::string const& _json)
{
js::mValue v;
js::read_string(_json, v);
for (auto const& i: v.get_array())
{
js::mObject o = i.get_obj();
if (o["type"].get_str() != "function")
continue;
ABIMethod m(o);
m_methods[m.id()] = m;
}
}
ABIMethod method(string _nameOrSig, vector<ABIType> const& _args) const
{
auto id = FixedHash<4>(sha3(_nameOrSig));
if (!m_methods.count(id))
id = FixedHash<4>(sha3(canonSig(_nameOrSig, _args)));
if (!m_methods.count(id))
for (auto const& m: m_methods)
if (m.second.name == _nameOrSig)
{
if (m_methods.count(id))
throw OverloadedMethod();
id = m.first;
}
if (m_methods.count(id))
return m_methods.at(id);
throw UnknownMethod();
}
friend ostream& operator<<(ostream& _out, ABI const& _abi);
private:
map<FixedHash<4>, ABIMethod> m_methods;
};
ostream& operator<<(ostream& _out, ABI const& _abi)
{
_out << "contract {" << endl;
for (auto const& i: _abi.m_methods)
_out << " " << i.second.solidityDeclaration() << "; // " << i.first.abridged() << endl;
_out << "}" << endl;
return _out;
}
void userOutput(ostream& _out, bytes const& _data, Encoding _e)
{
switch (_e)
{
case Encoding::Binary:
_out.write((char const*)_data.data(), _data.size());
break;
default:
_out << toHex(_data) << endl;
}
}
template <unsigned n, class T> vector<typename std::remove_reference<decltype(get<n>(T()))>::type> retrieve(vector<T> const& _t)
{
vector<typename std::remove_reference<decltype(get<n>(T()))>::type> ret;
for (T const& i: _t)
ret.push_back(get<n>(i));
return ret;
}
int main(int argc, char** argv)
{
Encoding encoding = Encoding::Auto;
Mode mode = Mode::Encode;
string abiFile;
string method;
Tristate formatPrefix = Tristate::Mu;
Tristate typePrefix = Tristate::Mu;
EncodingPrefs prefs;
bool verbose = false;
int outputIndex = -1;
vector<pair<bytes, Format>> params;
vector<ABIType> args;
string incoming;
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if (arg == "-h" || arg == "--help")
help();
else if (arg == "enc" && i == 1)
mode = Mode::Encode;
else if (arg == "dec" && i == 1)
mode = Mode::Decode;
else if ((arg == "-a" || arg == "--abi") && argc > i)
abiFile = argv[++i];
else if ((arg == "-i" || arg == "--index") && argc > i)
outputIndex = atoi(argv[++i]);
else if (arg == "-p" || arg == "--prefix")
prefs.prefix = true;
else if (arg == "-f" || arg == "--format-prefix")
formatPrefix = Tristate::True;
else if (arg == "-F" || arg == "--no-format-prefix")
formatPrefix = Tristate::False;
else if (arg == "-t" || arg == "--typing")
typePrefix = Tristate::True;
else if (arg == "-T" || arg == "--no-typing")
typePrefix = Tristate::False;
else if (arg == "-x" || arg == "--hex")
prefs.e = Encoding::Hex;
else if (arg == "-d" || arg == "--decimal" || arg == "--dec")
prefs.e = Encoding::Decimal;
else if (arg == "-b" || arg == "--binary" || arg == "--bin")
prefs.e = Encoding::Binary;
else if (arg == "-v" || arg == "--verbose")
verbose = true;
else if (arg == "-V" || arg == "--version")
version();
else if (method.empty())
method = arg;
else if (mode == Mode::Encode)
{
auto u = fromUser(arg, formatPrefix, typePrefix);
args.push_back(get<1>(u));
params.push_back(make_pair(get<0>(u), get<2>(u)));
}
else if (mode == Mode::Decode)
incoming += arg;
}
string abiData;
if (!abiFile.empty())
abiData = contentsString(abiFile);
if (mode == Mode::Encode)
{
ABIMethod m;
if (abiData.empty())
m = ABIMethod(method, args);
else
{
ABI abi(abiData);
if (verbose)
cerr << "ABI:" << endl << abi;
try {
m = abi.method(method, args);
}
catch (...)
{
cerr << "Unknown method in ABI." << endl;
exit(-1);
}
}
try {
userOutput(cout, m.encode(params), encoding);
}
catch (ExpectedAdditionalParameter const&)
{
cerr << "Expected additional parameter in input." << endl;
exit(-1);
}
catch (ExpectedOpen const&)
{
cerr << "Expected open-bracket '[' in input." << endl;
exit(-1);
}
catch (ExpectedClose const&)
{
cerr << "Expected close-bracket ']' in input." << endl;
exit(-1);
}
}
else if (mode == Mode::Decode)
{
if (abiData.empty())
{
cerr << "Please specify an ABI file." << endl;
exit(-1);
}
else
{
ABI abi(abiData);
ABIMethod m;
if (verbose)
cerr << "ABI:" << endl << abi;
try {
m = abi.method(method, args);
}
catch(...)
{
cerr << "Unknown method in ABI." << endl;
exit(-1);
}
string encoded;
if (incoming == "--" || incoming.empty())
for (int i = cin.get(); i != -1; i = cin.get())
encoded.push_back((char)i);
else
{
encoded = contentsString(incoming);
}
cout << m.decode(fromHex(boost::trim_copy(encoded)), outputIndex, prefs) << endl;
}
}
return 0;
}

6
alethzero/CMakeLists.txt

@ -19,6 +19,7 @@ find_package (Qt5WebEngine QUIET)
find_package (Qt5WebEngineWidgets QUIET)
qt5_wrap_ui(ui_Main.h Main.ui)
qt5_wrap_ui(ui_Connect.h Connect.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui)
@ -32,8 +33,8 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE}
ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Debugger.ui Transact.ui
ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui
WIN_RESOURCES alethzero.rc
)
@ -56,6 +57,7 @@ target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} jsqrc)
target_link_libraries(${EXECUTABLE} natspec)
target_link_libraries(${EXECUTABLE} ${MHD_LIBRARIES})
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
target_link_libraries(${EXECUTABLE} serpent)

64
alethzero/Connect.cpp

@ -0,0 +1,64 @@
/*
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 Connect.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#include "Connect.h"
#include <libp2p/Host.h>
#include "ui_Connect.h"
Connect::Connect(QWidget *parent) :
QDialog(parent),
ui(new Ui::Connect)
{
ui->setupUi(this);
}
Connect::~Connect()
{
delete ui;
}
void Connect::setEnvironment(QStringList const& _nodes)
{
if (ui->host->count() == 0)
ui->host->addItems(_nodes);
}
void Connect::reset()
{
ui->nodeId->clear();
ui->required->setChecked(true);
}
QString Connect::host()
{
return ui->host->currentText();
}
QString Connect::nodeId()
{
return ui->nodeId->text();
}
bool Connect::required()
{
return ui->required->isChecked();
}

55
alethzero/Connect.h

@ -0,0 +1,55 @@
/*
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 Connect.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#pragma once
#include <QDialog>
#include <QList>
namespace Ui { class Connect; }
namespace dev { namespace p2p { class Host; } }
class Connect : public QDialog
{
Q_OBJECT
public:
explicit Connect(QWidget* _parent = 0);
~Connect();
/// Populate host chooser with default host entries.
void setEnvironment(QStringList const& _nodes);
/// Clear dialogue inputs.
void reset();
/// @returns the host string, as chosen or entered by the user. Assumed to be "hostOrIP:port" (:port is optional).
QString host();
/// @returns the identity of the node, as entered by the user. Assumed to be a 64-character hex string.
QString nodeId();
/// @returns true if Required is checked by the user, indicating that the host is a required Peer.
bool required();
private:
Ui::Connect* ui;
};

126
alethzero/Connect.ui

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Connect</class>
<widget class="QDialog" name="Connect">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>343</width>
<height>178</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>343</width>
<height>178</height>
</size>
</property>
<property name="windowTitle">
<string>Connect to Peer</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="1" column="0">
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="host">
<property name="minimumSize">
<size>
<width>311</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLineEdit" name="nodeId">
<property name="placeholderText">
<string>Node Id</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="required">
<property name="text">
<string>Required (Always Connect to this Peer)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="formLabel">
<property name="text">
<string>Enter a peer to which a connection may be made:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Connect</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Connect</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

139
alethzero/DappHost.cpp

@ -0,0 +1,139 @@
/*
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 DappHost.cpp
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#include "DappHost.h"
#include <QUrl>
#include <microhttpd.h>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Common.h>
using namespace dev;
DappHost::DappHost(int _port, int _threads):
m_port(_port), m_threads(_threads), m_running(false), m_daemon(nullptr)
{
startListening();
}
DappHost::~DappHost()
{
stopListening();
}
void DappHost::startListening()
{
if(!this->m_running)
{
this->m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, this->m_port, nullptr, nullptr, &DappHost::callback, this, MHD_OPTION_THREAD_POOL_SIZE, this->m_threads, MHD_OPTION_END);
if (this->m_daemon != nullptr)
this->m_running = true;
}
}
void DappHost::stopListening()
{
if(this->m_running)
{
MHD_stop_daemon(this->m_daemon);
this->m_running = false;
}
}
void DappHost::sendOptionsResponse(MHD_Connection* _connection)
{
MHD_Response *result = MHD_create_response_from_data(0, NULL, 0, 1);
MHD_add_response_header(result, "Allow", "GET, OPTIONS");
MHD_add_response_header(result, "Access-Control-Allow-Headers", "origin, content-type, accept");
MHD_add_response_header(result, "DAV", "1");
MHD_queue_response(_connection, MHD_HTTP_OK, result);
MHD_destroy_response(result);
}
void DappHost::sendNotAllowedResponse(MHD_Connection* _connection)
{
MHD_Response *result = MHD_create_response_from_data(0, NULL, 0, 1);
MHD_add_response_header(result, "Allow", "GET, OPTIONS");
MHD_queue_response(_connection, MHD_HTTP_METHOD_NOT_ALLOWED, result);
MHD_destroy_response(result);
}
void DappHost::sendResponse(std::string const& _url, MHD_Connection* _connection)
{
QUrl requestUrl(QString::fromStdString(_url));
QString path = requestUrl.path().toLower();
if (path.isEmpty())
path = "/";
bytesConstRef response;
unsigned code = MHD_HTTP_NOT_FOUND;
std::string contentType;
while (!path.isEmpty())
{
auto iter = m_entriesByPath.find(path);
if (iter != m_entriesByPath.end())
{
ManifestEntry const* entry = iter->second;
auto contentIter = m_dapp.content.find(entry->hash);
if (contentIter == m_dapp.content.end())
break;
response = bytesConstRef(contentIter->second.data(), contentIter->second.size());
code = entry->httpStatus != 0 ? entry->httpStatus : MHD_HTTP_OK;
contentType = entry->contentType;
break;
}
path.truncate(path.length() - 1);
path = path.mid(0, path.lastIndexOf('/'));
}
MHD_Response *result = MHD_create_response_from_data(response.size(), const_cast<byte*>(response.data()), 0, 1);
if (!contentType.empty())
MHD_add_response_header(result, "Content-Type", contentType.c_str());
MHD_queue_response(_connection, code, result);
MHD_destroy_response(result);
}
int DappHost::callback(void* _cls, MHD_Connection* _connection, char const* _url, char const* _method, char const* _version, char const* _uploadData, size_t* _uploadDataSize, void** _conCls)
{
(void)_version;
(void)_uploadData;
(void)_uploadDataSize;
(void)_conCls;
DappHost* host = static_cast<DappHost*>(_cls);
if (std::string("GET") == _method)
host->sendResponse(std::string(_url), _connection);
else if (std::string("OPTIONS") == _method)
host->sendOptionsResponse(_connection);
else
host->sendNotAllowedResponse(_connection);
return MHD_YES;
}
QUrl DappHost::hostDapp(Dapp&& _dapp)
{
m_dapp = std::move(_dapp);
m_entriesByPath.clear();
for (ManifestEntry const& entry: m_dapp.manifest.entries)
m_entriesByPath[QString::fromStdString(entry.path)] = &entry;
return QUrl(QString("http://localhost:%1/").arg(m_port));
}

58
alethzero/DappHost.h

@ -0,0 +1,58 @@
/*
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 DappHost.h
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#pragma once
#include <map>
#include <QUrl>
#include <QString>
#include "DappLoader.h"
struct MHD_Daemon;
struct MHD_Connection;
/// DApp web server. Servers web content, resolves paths by hashes
class DappHost
{
public:
/// @param _port Network pork to listen for incoming connections
/// @param _threads Max number of threads to process requests
DappHost(int _port, int _threads = 10);
virtual ~DappHost();
/// Load and host a dapp. Previsous dapp in discarded. Synchronous
QUrl hostDapp(Dapp&& _dapp);
private:
void startListening();
void stopListening();
void sendOptionsResponse(MHD_Connection* _connection);
void sendNotAllowedResponse(MHD_Connection* _connection);
void sendResponse(std::string const& _url, MHD_Connection* _connection);
static int callback(void* _cls, MHD_Connection* _connection, char const* _url, char const* _method, char const* _version, char const* _uploadData, size_t* _uploadDataSize, void** _conCls);
int m_port;
int m_threads;
bool m_running;
MHD_Daemon* m_daemon;
Dapp m_dapp;
std::map<QString, ManifestEntry const*> m_entriesByPath;
};

218
alethzero/DappLoader.cpp

@ -0,0 +1,218 @@
/*
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 DappLoader.cpp
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#include <algorithm>
#include <json/json.h>
#include <QUrl>
#include <QStringList>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h>
#include <libethcore/CommonJS.h>
#include <libethereum/Client.h>
#include <libwebthree/WebThree.h>
#include "DappLoader.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::crypto;
Address c_registrar = Address("0000000000000000000000000000000000000a28");
Address c_urlHint = Address("0000000000000000000000000000000000000a29");
QString contentsOfQResource(std::string const& res);
DappLoader::DappLoader(QObject* _parent, WebThreeDirect* _web3):
QObject(_parent), m_web3(_web3)
{
connect(&m_net, &QNetworkAccessManager::finished, this, &DappLoader::downloadComplete);
}
DappLocation DappLoader::resolveAppUri(QString const& _uri)
{
QUrl url(_uri);
if (!url.scheme().isEmpty() && url.scheme() != "eth")
throw dev::Exception(); //TODO:
QStringList parts = url.host().split('.', QString::SkipEmptyParts);
QStringList domainParts;
std::reverse(parts.begin(), parts.end());
parts.append(url.path().split('/', QString::SkipEmptyParts));
Address address = c_registrar;
Address lastAddress;
int partIndex = 0;
h256 contentHash;
while (address && partIndex < parts.length())
{
lastAddress = address;
string32 name = ZeroString32;
QByteArray utf8 = parts[partIndex].toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), name.data());
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("addr(string32)", name)).output);
domainParts.append(parts[partIndex]);
if (!address)
{
//we have the address of the last part, try to get content hash
contentHash = abiOut<h256>(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name)).output);
if (!contentHash)
throw dev::Exception() << errinfo_comment("Can't resolve address");
}
++partIndex;
}
string32 contentUrl = abiOut<string32>(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash)).output);
QString domain = domainParts.join('/');
parts.erase(parts.begin(), parts.begin() + partIndex);
QString path = parts.join('/');
QString contentUrlString = QString::fromUtf8(std::string(contentUrl.data(), contentUrl.size()).c_str());
if (!contentUrlString.startsWith("http://") || !contentUrlString.startsWith("https://"))
contentUrlString = "http://" + contentUrlString;
return DappLocation { domain, path, contentUrlString, contentHash };
}
void DappLoader::downloadComplete(QNetworkReply* _reply)
{
try
{
//try to interpret as rlp
QByteArray data = _reply->readAll();
_reply->deleteLater();
h256 expected = m_uriHashes[_reply->request().url()];
bytes package(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
Secp256k1 dec;
dec.decrypt(expected, package);
h256 got = sha3(package);
if (got != expected)
{
//try base64
data = QByteArray::fromBase64(data);
package = bytes(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
dec.decrypt(expected, package);
got = sha3(package);
if (got != expected)
throw dev::Exception() << errinfo_comment("Dapp content hash does not match");
}
RLP rlp(package);
loadDapp(rlp);
}
catch (...)
{
qWarning() << tr("Error downloading DApp: ") << boost::current_exception_diagnostic_information().c_str();
emit dappError();
}
}
void DappLoader::loadDapp(RLP const& _rlp)
{
Dapp dapp;
unsigned len = _rlp.itemCountStrict();
dapp.manifest = loadManifest(_rlp[0].toString());
for (unsigned c = 1; c < len; ++c)
{
bytesConstRef content = _rlp[c].toBytesConstRef();
h256 hash = sha3(content);
auto entry = std::find_if(dapp.manifest.entries.cbegin(), dapp.manifest.entries.cend(), [=](ManifestEntry const& _e) { return _e.hash == hash; });
if (entry != dapp.manifest.entries.cend())
{
if (entry->path == "/deployment.js")
{
//inject web3 code
QString code;
code += contentsOfQResource(":/js/bignumber.min.js");
code += "\n";
code += contentsOfQResource(":/js/webthree.js");
code += "\n";
code += contentsOfQResource(":/js/setup.js");
code += "\n";
QByteArray res = code.toLatin1();
bytes b(res.data(), res.data() + res.size());
b.insert(b.end(), content.begin(), content.end());
dapp.content[hash] = b;
}
else
dapp.content[hash] = content.toBytes();
}
else
throw dev::Exception() << errinfo_comment("Dapp content hash does not match");
}
emit dappReady(dapp);
}
Manifest DappLoader::loadManifest(std::string const& _manifest)
{
/// https://github.com/ethereum/go-ethereum/wiki/URL-Scheme
Manifest manifest;
Json::Reader jsonReader;
Json::Value root;
jsonReader.parse(_manifest, root, false);
Json::Value entries = root["entries"];
for (Json::ValueIterator it = entries.begin(); it != entries.end(); ++it)
{
Json::Value const& entryValue = *it;
std::string path = entryValue["path"].asString();
if (path.size() == 0 || path[0] != '/')
path = "/" + path;
std::string contentType = entryValue["contentType"].asString();
std::string strHash = entryValue["hash"].asString();
if (strHash.length() == 64)
strHash = "0x" + strHash;
h256 hash = jsToFixed<32>(strHash);
unsigned httpStatus = entryValue["status"].asInt();
manifest.entries.push_back(ManifestEntry{ path, hash, contentType, httpStatus });
}
return manifest;
}
void DappLoader::loadDapp(QString const& _uri)
{
QUrl uri(_uri);
QUrl contentUri;
h256 hash;
if (uri.path().endsWith(".dapp") && uri.query().startsWith("hash="))
{
contentUri = uri;
QString query = uri.query();
query.remove("hash=");
if (!query.startsWith("0x"))
query.insert(0, "0x");
hash = jsToFixed<32>(query.toStdString());
}
else
{
DappLocation location = resolveAppUri(_uri);
contentUri = location.contentUri;
hash = location.contentHash;
}
QNetworkRequest request(contentUri);
m_uriHashes[uri] = hash;
m_net.get(request);
}

94
alethzero/DappLoader.h

@ -0,0 +1,94 @@
/*
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 DappLoader.h
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#pragma once
#include <map>
#include <string>
#include <vector>
#include <QObject>
#include <QString>
#include <QUrl>
#include <QNetworkAccessManager>
#include <libdevcore/FixedHash.h>
namespace dev
{
class WebThreeDirect;
class RLP;
}
struct ManifestEntry
{
std::string path;
dev::h256 hash;
std::string contentType;
unsigned httpStatus;
};
struct Manifest
{
std::vector<ManifestEntry> entries;
};
struct Dapp
{
Manifest manifest;
std::map<dev::h256, dev::bytes> content;
};
struct DappLocation
{
QString canonDomain;
QString path;
QString contentUri;
dev::h256 contentHash;
};
///Downloads, unpacks and prepares DApps for hosting
class DappLoader: public QObject
{
Q_OBJECT
public:
DappLoader(QObject* _parent, dev::WebThreeDirect* _web3);
///Load a new DApp. Resolves a name with a name reg contract. Asynchronous. dappReady is emitted once everything is read, dappError othervise
///@param _uri Eth name path
void loadDapp(QString const& _uri);
signals:
void dappReady(Dapp& _dapp);
void dappError();
private slots:
void downloadComplete(QNetworkReply* _reply);
private:
dev::WebThreeDirect* web3() const { return m_web3; }
DappLocation resolveAppUri(QString const& _uri);
void loadDapp(dev::RLP const& _rlp);
Manifest loadManifest(std::string const& _manifest);
dev::WebThreeDirect* m_web3;
QNetworkAccessManager m_net;
std::map<QUrl, dev::h256> m_uriHashes;
};

3
alethzero/Debugger.cpp

@ -67,7 +67,8 @@ void Debugger::populate(dev::eth::Executive& _executive, dev::eth::Transaction c
bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction)
{
try {
if (_executive.setup(_transaction))
_executive.initialize(_transaction);
if (_executive.execute())
return false;
}
catch (...)

83
alethzero/Main.ui

@ -45,6 +45,13 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="chainStatus">
<property name="text">
<string>#0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="balance">
<property name="text">
@ -134,8 +141,7 @@
<addaction name="go"/>
<addaction name="separator"/>
<addaction name="upnp"/>
<addaction name="usePast"/>
<addaction name="localNetworking"/>
<addaction name="dropPeers"/>
<addaction name="net"/>
<addaction name="connect"/>
</widget>
@ -208,7 +214,7 @@
<addaction name="menu_Debug"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="dockWidget_2">
<widget class="QDockWidget" name="dockWidget_accounts">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
@ -284,7 +290,27 @@
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="2">
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Listen on</string>
</property>
<property name="buddy">
<cstring>port</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="port">
<property name="minimum">
<number>1024</number>
@ -297,8 +323,8 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="forceAddress">
<item row="3" column="1">
<widget class="QLineEdit" name="listenIP">
<property name="inputMask">
<string/>
</property>
@ -310,16 +336,6 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Listen on</string>
</property>
<property name="buddy">
<cstring>port</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
@ -330,20 +346,17 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
<item row="5" column="1">
<widget class="QLineEdit" name="forcePublicIP">
<property name="placeholderText">
<string>Automatic</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLineEdit" name="clientName">
<property name="placeholderText">
<string>Anonymous</string>
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Public IP</string>
</property>
</widget>
</item>
@ -357,6 +370,13 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="clientName">
<property name="placeholderText">
<string>Anonymous</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -566,7 +586,7 @@
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_6">
<widget class="QDockWidget" name="dockWidget_contracts">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
@ -1443,12 +1463,12 @@ font-size: 14pt</string>
<string>Show &amp;Anonymous Accounts</string>
</property>
</action>
<action name="usePast">
<action name="dropPeers">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Use &amp;Past Peers</string>
<string>&amp;Drop Past Peers</string>
</property>
</action>
<action name="loadJS">
@ -1694,9 +1714,8 @@ font-size: 14pt</string>
<tabstop>tabWidget</tabstop>
<tabstop>urlEdit</tabstop>
<tabstop>idealPeers</tabstop>
<tabstop>forceAddress</tabstop>
<tabstop>listenIP</tabstop>
<tabstop>port</tabstop>
<tabstop>clientName</tabstop>
<tabstop>transactionQueue</tabstop>
<tabstop>pendingInfo</tabstop>
<tabstop>blockChainFilter</tabstop>

451
alethzero/MainWin.cpp

@ -19,7 +19,6 @@
* @date 2014
*/
#define QWEBENGINEINSPECTOR 1
#include <fstream>
// Make sure boost/asio.hpp is included before windows.h.
@ -29,6 +28,7 @@
//pragma GCC diagnostic ignored "-Werror=pedantic"
#include <QtNetwork/QNetworkReply>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog>
#include <QtWebEngine/QtWebEngine>
@ -68,6 +68,9 @@
#include "OurWebThreeStubServer.h"
#include "Transact.h"
#include "Debugger.h"
#include "DappLoader.h"
#include "DappHost.h"
#include "WebPage.h"
#include "ui_Main.h"
using namespace std;
using namespace dev;
@ -116,7 +119,9 @@ Address c_newConfig = Address("c6d9d2cd449a754c494264e1809c50e34d64562b");
Main::Main(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Main),
m_transact(this, this)
m_transact(this, this),
m_dappLoader(nullptr),
m_webPage(nullptr)
{
QtWebEngine::initialize();
setWindowFlags(Qt::Window);
@ -131,17 +136,22 @@ Main::Main(QWidget *parent) :
// ui->log->addItem(QString::fromStdString(s));
};
#if !ETH_FATDB
delete ui->dockWidget_accounts;
delete ui->dockWidget_contracts;
#endif
#if ETH_DEBUG
m_servers.append("localhost:30300");
m_servers.append("127.0.0.1:30300");
#endif
m_servers.append(QString::fromStdString(Host::pocHost() + ":30303"));
cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl;
auto block = CanonBlockChain::createGenesisBlock();
cerr << "Block Hash: " << CanonBlockChain::genesis().hash << endl;
cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl;
cerr << "Block RLP: " << RLP(block) << endl;
cerr << "Block Hex: " << toHex(block) << endl;
cerr << "Network protocol version: " << c_protocolVersion << endl;
cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl;
cerr << "Client database version: " << c_databaseVersion << endl;
ui->configDock->close();
@ -151,25 +161,30 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->mineStatus);
statusBar()->addPermanentWidget(ui->chainStatus);
statusBar()->addPermanentWidget(ui->blockCount);
ui->blockCount->setText(QString("PV%2 D%3 H%4 v%5").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(c_ethashVersion).arg(dev::Version));
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray();
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"}, p2p::NetworkPreferences(), network));
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth", "shh"}, p2p::NetworkPreferences(), network));
m_httpConnector.reset(new jsonrpc::HttpServer(8080));
m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads));
m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), keysAsVector(m_myKeys), this));
connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString)));
m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening();
WebPage* webPage= new WebPage(this);
m_webPage = webPage;
connect(webPage, &WebPage::consoleMessage, [this](QString const& _msg) { Main::addConsoleMessage(_msg, QString()); });
ui->webView->setPage(m_webPage);
connect(ui->webView, &QWebEngineView::loadFinished, [this]()
{
// f->disconnect();
// f->addToJavaScriptWindowObject("env", this, QWebFrame::QtOwnership);
auto f = ui->webView->page();
f->runJavaScript(contentsOfQResource(":/js/bignumber.min.js"));
f->runJavaScript(contentsOfQResource(":/js/webthree.js"));
@ -181,6 +196,9 @@ Main::Main(QWidget *parent) :
ui->tabWidget->setTabText(0, ui->webView->title());
});
m_dappHost.reset(new DappHost(8081));
m_dappLoader = new DappLoader(this, web3());
connect(m_dappLoader, &DappLoader::dappReady, this, &Main::dappLoaded);
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page);
@ -237,7 +255,30 @@ void Main::addNewId(QString _ids)
NetworkPreferences Main::netPrefs() const
{
return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked());
auto listenIP = ui->listenIP->text().toStdString();
try
{
listenIP = bi::address::from_string(listenIP).to_string();
}
catch (...)
{
listenIP.clear();
}
auto publicIP = ui->forcePublicIP->text().toStdString();
try
{
publicIP = bi::address::from_string(publicIP).to_string();
}
catch (...)
{
publicIP.clear();
}
if (isPublicAddress(publicIP))
return NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
else
return NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked());
}
void Main::onKeysChanged()
@ -247,40 +288,51 @@ void Main::onKeysChanged()
unsigned Main::installWatch(LogFilter const& _tf, WatchHandler const& _f)
{
auto ret = ethereum()->installWatch(_tf);
auto ret = ethereum()->installWatch(_tf, Reaping::Manual);
m_handlers[ret] = _f;
_f(LocalisedLogEntries());
return ret;
}
unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f)
{
auto ret = ethereum()->installWatch(_tf);
auto ret = ethereum()->installWatch(_tf, Reaping::Manual);
m_handlers[ret] = _f;
_f(LocalisedLogEntries());
return ret;
}
void Main::uninstallWatch(unsigned _w)
{
cdebug << "!!! Main: uninstalling watch" << _w;
ethereum()->uninstallWatch(_w);
m_handlers.erase(_w);
}
void Main::installWatches()
{
auto newBlockId = installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){
onNewBlock();
});
auto newPendingId = installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){
onNewPending();
});
cdebug << "newBlock watch ID: " << newBlockId;
cdebug << "newPending watch ID: " << newPendingId;
installWatch(LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installNameRegWatch(); });
installWatch(LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installCurrenciesWatch(); });
installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ onNewPending(); });
installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); });
}
Address Main::getNameReg() const
{
return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)));
return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)).output);
}
Address Main::getCurrencies() const
{
return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3)));
return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3)).output);
}
void Main::installNameRegWatch()
@ -303,7 +355,7 @@ void Main::installBalancesWatch()
Address coinsAddr = getCurrencies();
// TODO: Update for new currencies reg.
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i)
altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys)
for (auto c: altCoins)
@ -425,13 +477,7 @@ void Main::eval(QString const& _js)
s = "<span style=\"color: #840\">" + jsonEv.toString().toHtmlEscaped() + "</span>";
else
s = "<span style=\"color: #888\">unknown type</span>";
m_consoleHistory.push_back(qMakePair(_js, s));
s = "<html><body style=\"margin: 0;\">" Div(Mono "position: absolute; bottom: 0; border: 0px; margin: 0px; width: 100%");
for (auto const& i: m_consoleHistory)
s += "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em; color: #888; font-weight: bold\">&gt;</span><span style=\"color: #35d\">" + i.first.toHtmlEscaped() + "</span></div>"
"<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em\">&nbsp;</span><span>" + i.second + "</span></div>";
s += "</div></body></html>";
ui->jsConsole->setHtml(s);
addConsoleMessage(_js, s);
};
ui->webView->page()->runJavaScript("JSON.stringify(___RET)", f2);
};
@ -439,6 +485,17 @@ void Main::eval(QString const& _js)
ui->webView->page()->runJavaScript(c, f);
}
void Main::addConsoleMessage(QString const& _js, QString const& _s)
{
m_consoleHistory.push_back(qMakePair(_js, _s));
QString r = "<html><body style=\"margin: 0;\">" Div(Mono "position: absolute; bottom: 0; border: 0px; margin: 0px; width: 100%");
for (auto const& i: m_consoleHistory)
r += "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em; color: #888; font-weight: bold\">&gt;</span><span style=\"color: #35d\">" + i.first.toHtmlEscaped() + "</span></div>"
"<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em\">&nbsp;</span><span>" + i.second + "</span></div>";
r += "</div></body></html>";
ui->jsConsole->setHtml(r);
}
static Public stringToPublic(QString const& _a)
{
string sn = _a.toStdString();
@ -456,7 +513,7 @@ QString Main::pretty(dev::Address _a) const
if (g_newNameReg)
{
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)))));
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)).output)));
if (s.size())
return s;
}
@ -464,10 +521,83 @@ QString Main::pretty(dev::Address _a) const
return fromRaw(n);
}
template <size_t N> inline string toBase36(FixedHash<N> const& _h)
{
static char const* c_alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
typename FixedHash<N>::Arith a = _h;
std::string ret;
for (; a > 0; a /= 36)
ret = c_alphabet[(unsigned)a % 36] + ret;
return ret;
}
template <size_t N> inline FixedHash<N> fromBase36(string const& _h)
{
typename FixedHash<N>::Arith ret = 0;
for (char c: _h)
ret = ret * 36 + (c < 'A' ? c - '0' : (c - 'A' + 10));
return ret;
}
static string iban(std::string _c, std::string _d)
{
boost::to_upper(_c);
boost::to_upper(_d);
auto totStr = _d + _c + "00";
bigint tot = 0;
for (char x: totStr)
if (x >= 'A')
tot = tot * 100 + x - 'A' + 10;
else
tot = tot * 10 + x - '0';
unsigned check = (unsigned)(u256)(98 - tot % 97);
ostringstream out;
out << _c << setfill('0') << setw(2) << check << _d;
return out.str();
}
static std::pair<string, string> fromIban(std::string _iban)
{
if (_iban.size() < 4)
return std::make_pair(string(), string());
boost::to_upper(_iban);
std::string c = _iban.substr(0, 2);
std::string d = _iban.substr(4);
if (iban(c, d) != _iban)
return std::make_pair(string(), string());
return make_pair(c, d);
}
static string directICAP(dev::Address _a)
{
if (!!_a[0])
return string();
std::string d = toBase36<Address::size>(_a);
while (d.size() < 30)
d = "0" + d;
return iban("XE", d);
}
static Address fromICAP(std::string const& _s)
{
std::string country;
std::string data;
std::tie(country, data) = fromIban(_s);
if (country.empty())
return Address();
if (country == "XE" && data.size() == 30)
// Direct ICAP
return fromBase36<Address::size>(data);
// TODO: Indirect ICAP
return Address();
}
QString Main::render(dev::Address _a) const
{
QString p = pretty(_a);
if (!p.isNull())
if (!_a[0])
p += QString(p.isEmpty() ? "" : " ") + QString::fromStdString(directICAP(_a));
if (!p.isEmpty())
return p + " (" + QString::fromStdString(_a.abridged()) + ")";
return QString::fromStdString(_a.abridged());
}
@ -488,7 +618,7 @@ Address Main::fromString(QString const& _n) const
auto g_newNameReg = getNameReg();
if (g_newNameReg)
{
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))));
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))).output);
if (a)
return a;
}
@ -496,7 +626,7 @@ Address Main::fromString(QString const& _n) const
{
try
{
return Address(fromHex(_n.toStdString(), ThrowType::Throw));
return Address(fromHex(_n.toStdString(), WhenError::Throw));
}
catch (BadHexCharacter& _e)
{
@ -510,6 +640,8 @@ Address Main::fromString(QString const& _n) const
return Address();
}
}
else if (Address a = fromICAP(_n.toStdString()))
return a;
else
return Address();
}
@ -527,10 +659,10 @@ QString Main::lookup(QString const& _a) const
h256 ret;
// TODO: fix with the new DNSreg contract
// if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0))
// if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, PendingBlock))
// ret = ethereum()->stateAt(dnsReg, n);
/* if (!ret)
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0, 0))
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0, PendingBlock))
ret = ethereum()->stateAt(nameReg, n2);
*/
if (ret && !((u256)ret >> 32))
@ -579,9 +711,7 @@ void Main::writeSettings()
}
s.setValue("upnp", ui->upnp->isChecked());
s.setValue("forceAddress", ui->forceAddress->text());
s.setValue("usePast", ui->usePast->isChecked());
s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceAddress", ui->forcePublicIP->text());
s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("natSpec", ui->natSpec->isChecked());
@ -589,6 +719,7 @@ void Main::writeSettings()
s.setValue("showAllAccounts", ui->showAllAccounts->isChecked());
s.setValue("clientName", ui->clientName->text());
s.setValue("idealPeers", ui->idealPeers->value());
s.setValue("listenIP", ui->listenIP->text());
s.setValue("port", ui->port->value());
s.setValue("url", ui->urlEdit->text());
s.setValue("privateChain", m_privateChain);
@ -648,9 +779,8 @@ void Main::readSettings(bool _skipGeometry)
}
ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString());
ui->usePast->setChecked(s.value("usePast", true).toBool());
ui->localNetworking->setChecked(s.value("localNetworking", true).toBool());
ui->forcePublicIP->setText(s.value("forceAddress", "").toString());
ui->dropPeers->setChecked(false);
ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool());
@ -661,6 +791,7 @@ void Main::readSettings(bool _skipGeometry)
if (ui->clientName->text().isEmpty())
ui->clientName->setText(QInputDialog::getText(nullptr, "Enter identity", "Enter a name that will identify you on the peer network"));
ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt());
ui->listenIP->setText(s.value("listenIP", "").toString());
ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString());
m_privateChain = s.value("privateChain", "").toString();
@ -729,7 +860,7 @@ void Main::on_importKeyFile_triggered()
m_myKeys.push_back(KeyPair::create());
keysChanged();
}
ethereum()->transact(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice());
ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice());
}
else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
@ -780,15 +911,28 @@ void Main::on_jitvm_triggered()
void Main::on_urlEdit_returnPressed()
{
QString s = ui->urlEdit->text();
QRegExp r("([a-z]+://)?([^/]*)(.*)");
if (r.exactMatch(s))
if (r.cap(2).isEmpty())
s = (r.cap(1).isEmpty() ? "file://" : r.cap(1)) + r.cap(3);
QUrl url(s);
if (url.scheme().isEmpty() || url.scheme() == "eth" || url.path().endsWith(".dapp"))
{
try
{
//try do resolve dapp url
m_dappLoader->loadDapp(s);
}
catch (...)
{
qWarning() << boost::current_exception_diagnostic_information().c_str();
}
}
if (url.scheme().isEmpty())
if (url.path().indexOf('/') < url.path().indexOf('.'))
url.setScheme("file");
else
s = (r.cap(1).isEmpty() ? "http://" : r.cap(1)) + lookup(r.cap(2)) + r.cap(3);
else{}
qDebug() << s;
ui->webView->setUrl(s);
url.setScheme("http");
else {}
qDebug() << url.toString();
ui->webView->page()->setUrl(url);
}
void Main::on_nameReg_textChanged()
@ -805,7 +949,7 @@ void Main::on_nameReg_textChanged()
void Main::on_preview_triggered()
{
ethereum()->setDefault(ui->preview->isChecked() ? 0 : -1);
ethereum()->setDefault(ui->preview->isChecked() ? PendingBlock : LatestBlock);
refreshAll();
}
@ -835,7 +979,7 @@ void Main::refreshBalances()
u256 totalBalance = 0;
/* map<Address, tuple<QString, u256, u256>> altCoins;
Address coinsAddr = getCurrencies();
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i)
{
auto n = ethereum()->stateAt(coinsAddr, i + 1);
auto addr = right160(ethereum()->stateAt(coinsAddr, n));
@ -934,6 +1078,7 @@ void Main::refreshPending()
void Main::refreshAccounts()
{
#if ETH_FATDB
cwatch << "refreshAccounts()";
ui->accounts->clear();
ui->contracts->clear();
@ -951,14 +1096,14 @@ void Main::refreshAccounts()
->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size));
}
}
#endif
}
void Main::refreshBlockCount()
{
cwatch << "refreshBlockCount()";
auto d = ethereum()->blockChain().details();
auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty;
ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet"));
BlockQueueStatus b = ethereum()->blockQueueStatus();
ui->chainStatus->setText(QString("%3 ready %4 future %5 unknown %6 bad %1 #%2").arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.ready).arg(b.future).arg(b.unknown).arg(b.bad));
}
void Main::on_turboMining_triggered()
@ -973,7 +1118,7 @@ void Main::refreshBlockChain()
// TODO: keep the same thing highlighted.
// TODO: refactor into MVC
// TODO: use get by hash/number
// TODO: transactions, log addresses, log topics
// TODO: transactions
auto const& bc = ethereum()->blockChain();
QStringList filters = ui->blockChainFilter->text().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
@ -985,15 +1130,17 @@ void Main::refreshBlockChain()
h256 h(f.toStdString());
if (bc.isKnown(h))
blocks.insert(h);
for (auto const& b: bc.withBlockBloom(LogBloom().shiftBloom<3>(sha3(h)), 0, -1))
blocks.insert(bc.numberHash(b));
}
else if (f.toLongLong() <= bc.number())
blocks.insert(bc.numberHash(u256(f.toLongLong())));
/*else if (f.size() == 40)
blocks.insert(bc.numberHash((unsigned)f.toLongLong()));
else if (f.size() == 40)
{
Address h(f[0]);
if (bc.(h))
blocks.insert(h);
}*/
Address h(f.toStdString());
for (auto const& b: bc.withBlockBloom(LogBloom().shiftBloom<3>(sha3(h)), 0, -1))
blocks.insert(bc.numberHash(b));
}
QByteArray oldSelected = ui->blocks->count() ? ui->blocks->currentItem()->data(Qt::UserRole).toByteArray() : QByteArray();
ui->blocks->clear();
@ -1135,6 +1282,7 @@ void Main::timerEvent(QTimerEvent*)
refreshNetwork();
refreshWhispers();
refreshCache();
refreshBlockCount();
poll();
}
else
@ -1142,7 +1290,7 @@ void Main::timerEvent(QTimerEvent*)
for (auto const& i: m_handlers)
{
auto ls = ethereum()->checkWatch(i.first);
auto ls = ethereum()->checkWatchSafe(i.first);
if (ls.size())
{
cnote << "FIRING WATCH" << i.first << ls.size();
@ -1247,11 +1395,14 @@ void Main::on_transactionQueue_currentItemChanged()
}
s << "<div>Hex: " Span(Mono) << toHex(tx.rlp()) << "</span></div>";
s << "<hr/>";
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
if (!!receipt.bloom())
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
else
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "</span></div>";
s << renderDiff(ethereum()->diff(i, 0));
s << renderDiff(ethereum()->diff(i, PendingBlock));
// s << "Pre: " << fs.rootHash() << "<br/>";
// s << "Post: <b>" << ts.rootHash() << "</b>";
}
@ -1282,7 +1433,7 @@ void Main::on_inject_triggered()
QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex");
try
{
bytes b = fromHex(s.toStdString(), ThrowType::Throw);
bytes b = fromHex(s.toStdString(), WhenError::Throw);
ethereum()->inject(&b);
}
catch (BadHexCharacter& _e)
@ -1322,57 +1473,64 @@ void Main::on_blocks_currentItemChanged()
s << "<h3>" << h << "</h3>";
s << "<h4>#" << info.number;
s << "&nbsp;&emsp;&nbsp;<b>" << timestamp << "</b></h4>";
s << "<br/>D/TD: <b>2^" << log2((double)info.difficulty) << "</b>/<b>2^" << log2((double)details.totalDifficulty) << "</b>";
s << "&nbsp;&emsp;&nbsp;Children: <b>" << details.children.size() << "</b></h5>";
s << "<br/>Gas used/limit: <b>" << info.gasUsed << "</b>/<b>" << info.gasLimit << "</b>";
s << "<br/>Coinbase: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << info.coinbaseAddress;
s << "<br/>Seed hash: <b>" << info.seedHash << "</b>";
s << "<br/>Mix hash: <b>" << info.mixHash << "</b>";
s << "<br/>Nonce: <b>" << info.nonce << "</b>";
s << "<br/>Hash w/o nonce: <b>" << info.headerHash(WithoutNonce) << "</b>";
s << "<br/>Difficulty: <b>" << info.difficulty << "</b>";
s << "<div>D/TD: <b>" << info.difficulty << "</b>/<b>" << details.totalDifficulty << "</b> = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "</div>";
s << "&nbsp;&emsp;&nbsp;Children: <b>" << details.children.size() << "</b></div>";
s << "<div>Gas used/limit: <b>" << info.gasUsed << "</b>/<b>" << info.gasLimit << "</b>" << "</div>";
s << "<div>Beneficiary: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress << "</b>" << "</div>";
s << "<div>Seed hash: <b>" << info.seedHash() << "</b>" << "</div>";
s << "<div>Mix hash: <b>" << info.mixHash << "</b>" << "</div>";
s << "<div>Nonce: <b>" << info.nonce << "</b>" << "</div>";
s << "<div>Hash w/o nonce: <b>" << info.headerHash(WithoutNonce) << "</b>" << "</div>";
s << "<div>Difficulty: <b>" << info.difficulty << "</b>" << "</div>";
if (info.number)
{
auto e = Ethasher::eval(info);
s << "<br/>Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")";
s << "<div>Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")" << "</div>";
s << "<div>Parent: <b>" << info.parentHash << "</b>" << "</div>";
}
else
s << "<br/>Proof-of-Work: <i>Phil has nothing to prove</i>";
s << "<br/>Parent: <b>" << info.parentHash << "</b>";
// s << "<br/>Bloom: <b>" << details.bloom << "</b>";
s << "<br/>Log Bloom: <b>" << info.logBloom << "</b>";
s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>";
s << "<br/>Receipts: @<b>" << info.receiptsRoot << "</b>:";
s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>";
{
s << "<div>Proof-of-Work: <b><i>Phil has nothing to prove</i></b></div>";
s << "<div>Parent: <b><i>It was a virgin birth</i></b></div>";
}
// s << "<div>Bloom: <b>" << details.bloom << "</b>";
if (!!info.logBloom)
s << "<div>Log Bloom: " << info.logBloom << "</div>";
else
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
s << "<div>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>" << "</div>";
s << "<div>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>" << "</div>";
for (auto u: block[2])
{
BlockInfo uncle = BlockInfo::fromHeader(u.data());
char const* line = "<br/><span style=\"margin-left: 2em\">&nbsp;</span>";
s << line << "Hash: <b>" << uncle.hash << "</b>";
s << line << "Parent: <b>" << uncle.parentHash << "</b>";
s << line << "Number: <b>" << uncle.number << "</b>";
s << line << "Coinbase: <b>" << pretty(uncle.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << uncle.coinbaseAddress;
s << line << "Seed hash: <b>" << uncle.seedHash << "</b>";
s << line << "Mix hash: <b>" << uncle.mixHash << "</b>";
s << line << "Nonce: <b>" << uncle.nonce << "</b>";
s << line << "Hash w/o nonce: <b>" << uncle.headerHash(WithoutNonce) << "</b>";
s << line << "Difficulty: <b>" << uncle.difficulty << "</b>";
char const* line = "<div><span style=\"margin-left: 2em\">&nbsp;</span>";
s << line << "Hash: <b>" << uncle.hash() << "</b>" << "</div>";
s << line << "Parent: <b>" << uncle.parentHash << "</b>" << "</div>";
s << line << "Number: <b>" << uncle.number << "</b>" << "</div>";
s << line << "Coinbase: <b>" << pretty(uncle.coinbaseAddress).toHtmlEscaped().toStdString() << " " << uncle.coinbaseAddress << "</b>" << "</div>";
s << line << "Seed hash: <b>" << uncle.seedHash() << "</b>" << "</div>";
s << line << "Mix hash: <b>" << uncle.mixHash << "</b>" << "</div>";
s << line << "Nonce: <b>" << uncle.nonce << "</b>" << "</div>";
s << line << "Hash w/o nonce: <b>" << uncle.headerHash(WithoutNonce) << "</b>" << "</div>";
s << line << "Difficulty: <b>" << uncle.difficulty << "</b>" << "</div>";
auto e = Ethasher::eval(uncle);
s << line << "Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")";
s << line << "Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")" << "</div>";
}
if (info.parentHash)
s << "<br/>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "</b>";
s << "<div>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "</b>" << "</div>";
else
s << "<br/>Pre: <i>Nothing is before Phil</i>";
s << "<div>Pre: <b><i>Nothing is before Phil</i></b>" << "</div>";
s << "<div>Receipts: @<b>" << info.receiptsRoot << "</b>:" << "</div>";
BlockReceipts receipts = ethereum()->blockChain().receipts(h);
unsigned ii = 0;
for (auto const& i: block[1])
{
s << "<br/>" << sha3(i.data()).abridged() << ": <b>" << receipts.receipts[ii].stateRoot() << "</b> [<b>" << receipts.receipts[ii].gasUsed() << "</b> used]";
s << "<div>" << sha3(i.data()).abridged() << ": <b>" << receipts.receipts[ii].stateRoot() << "</b> [<b>" << receipts.receipts[ii].gasUsed() << "</b> used]" << "</div>";
++ii;
}
s << "<br/>Post: <b>" << info.stateRoot << "</b>";
s << "<br/>Dump: " Span(Mono) << toHex(block[0].data()) << "</span>";
s << "<div>Post: <b>" << info.stateRoot << "</b>" << "</div>";
s << "<div>Dump: " Span(Mono) << toHex(block[0].data()) << "</span>" << "</div>";
s << "<div>Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "</span></div>";
}
else
@ -1384,36 +1542,36 @@ void Main::on_blocks_currentItemChanged()
TransactionReceipt receipt = ethereum()->blockChain().receipts(h).receipts[txi];
s << "<h3>" << th << "</h3>";
s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>";
s << "<br/>From: <b>" << pretty(ss).toHtmlEscaped().toStdString() << "</b> " << ss;
s << "<div>From: <b>" << pretty(ss).toHtmlEscaped().toStdString() << " " << ss << "</b>" << "</div>";
if (tx.isCreation())
s << "<br/>Creates: <b>" << pretty(right160(th)).toHtmlEscaped().toStdString() << "</b> " << right160(th);
s << "<div>Creates: <b>" << pretty(right160(th)).toHtmlEscaped().toStdString() << "</b> " << right160(th) << "</div>";
else
s << "<br/>To: <b>" << pretty(tx.receiveAddress()).toHtmlEscaped().toStdString() << "</b> " << tx.receiveAddress();
s << "<br/>Value: <b>" << formatBalance(tx.value()) << "</b>";
s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce() << "</b>";
s << "<br/>Gas price: <b>" << formatBalance(tx.gasPrice()) << "</b>";
s << "<br/>Gas: <b>" << tx.gas() << "</b>";
s << "<br/>V: <b>" << hex << nouppercase << (int)tx.signature().v << " + 27</b>";
s << "<br/>R: <b>" << hex << nouppercase << tx.signature().r << "</b>";
s << "<br/>S: <b>" << hex << nouppercase << tx.signature().s << "</b>";
s << "<br/>Msg: <b>" << tx.sha3(eth::WithoutSignature) << "</b>";
if (tx.isCreation())
s << "<div>To: <b>" << pretty(tx.receiveAddress()).toHtmlEscaped().toStdString() << "</b> " << tx.receiveAddress() << "</div>";
s << "<div>Value: <b>" << formatBalance(tx.value()) << "</b>" << "</div>";
s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce() << "</b>" << "</div>";
s << "<div>Gas price: <b>" << formatBalance(tx.gasPrice()) << "</b>" << "</div>";
s << "<div>Gas: <b>" << tx.gas() << "</b>" << "</div>";
s << "<div>V: <b>" << hex << nouppercase << (int)tx.signature().v << " + 27</b>" << "</div>";
s << "<div>R: <b>" << hex << nouppercase << tx.signature().r << "</b>" << "</div>";
s << "<div>S: <b>" << hex << nouppercase << tx.signature().s << "</b>" << "</div>";
s << "<div>Msg: <b>" << tx.sha3(eth::WithoutSignature) << "</b>" << "</div>";
if (!tx.data().empty())
{
if (tx.data().size())
if (tx.isCreation())
s << "<h4>Code</h4>" << disassemble(tx.data());
}
else
{
if (tx.data().size())
s << dev::memDump(tx.data(), 16, true);
else
s << "<h4>Data</h4>" << dev::memDump(tx.data(), 16, true);
}
s << "<div>Hex: " Span(Mono) << toHex(block[1][txi].data()) << "</span></div>";
s << "<hr/>";
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
if (!!receipt.bloom())
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
else
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "</span></div>";
s << renderDiff(ethereum()->diff(txi, h));
s << "<h4>Diff</h4>" << renderDiff(ethereum()->diff(txi, h));
ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true);
ui->debugDumpStatePre->setEnabled(true);
@ -1437,7 +1595,7 @@ void Main::on_debugCurrent_triggered()
unsigned txi = item->data(Qt::UserRole + 1).toInt();
bytes t = ethereum()->blockChain().transaction(h, txi);
State s(ethereum()->state(txi, h));
Executive e(s, ethereum()->blockChain(), 0);
Executive e(s, ethereum()->blockChain());
Debugger dw(this, this);
dw.populate(e, Transaction(t, CheckSignature::Sender));
dw.exec();
@ -1513,16 +1671,22 @@ void Main::on_ourAccounts_doubleClicked()
void Main::on_accounts_doubleClicked()
{
auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
if (ui->accounts->count())
{
auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
}
void Main::on_contracts_doubleClicked()
{
auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
if (ui->contracts->count())
{
auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
}
}
static shh::FullTopic topicFromText(QString _s)
@ -1615,17 +1779,15 @@ void Main::on_net_triggered()
if (ui->net->isChecked())
{
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256());
// TODO: p2p
// if (m_networkConfig.size()/* && ui->usePast->isChecked()*/)
// web3()->restoreNetwork(bytesConstRef((byte*)m_networkConfig.data(), m_networkConfig.size()));
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
}
else
{
ui->downloadView->setDownloadMan(nullptr);
writeSettings();
web3()->stopNetwork();
}
}
@ -1637,13 +1799,25 @@ void Main::on_connect_triggered()
ui->net->setChecked(true);
on_net_triggered();
}
bool ok = false;
QString s = QInputDialog::getItem(this, "Connect to a Network Peer", "Enter a peer to which a connection may be made:", m_servers, m_servers.count() ? rand() % m_servers.count() : 0, true, &ok);
if (ok && s.contains(":"))
m_connect.setEnvironment(m_servers);
if (m_connect.exec() == QDialog::Accepted)
{
string host = s.section(":", 0, 0).toStdString();
unsigned short port = s.section(":", 1).toInt();
web3()->connect(host, port);
bool required = m_connect.required();
string host(m_connect.host().toStdString());
NodeId nodeID;
try
{
nodeID = NodeId(fromHex(m_connect.nodeId().toStdString()));
}
catch (BadHexCharacter&) {}
m_connect.reset();
if (required)
web3()->requirePeer(nodeID, host);
else
web3()->addNode(nodeID, host);
}
}
@ -1681,9 +1855,9 @@ bool beginsWith(Address _a, bytes const& _b)
void Main::on_newAccount_triggered()
{
bool ok = true;
enum { NoVanity = 0, FirstTwo, FirstTwoNextTwo, FirstThree, FirstFour, StringMatch };
QStringList items = {"No vanity (instant)", "Two pairs first (a few seconds)", "Two pairs first and second (a few minutes)", "Three pairs first (a few minutes)", "Four pairs first (several hours)", "Specific hex string"};
unsigned v = items.QList<QString>::indexOf(QInputDialog::getItem(this, "Vanity Key?", "Would you a vanity key? This could take several hours.", items, 0, false, &ok));
enum { NoVanity = 0, DirectICAP, FirstTwo, FirstTwoNextTwo, FirstThree, FirstFour, StringMatch };
QStringList items = {"No vanity (instant)", "Direct ICAP address", "Two pairs first (a few seconds)", "Two pairs first and second (a few minutes)", "Three pairs first (a few minutes)", "Four pairs first (several hours)", "Specific hex string"};
unsigned v = items.QList<QString>::indexOf(QInputDialog::getItem(this, "Vanity Key?", "Would you a vanity key? This could take several hours.", items, 1, false, &ok));
if (!ok)
return;
@ -1709,6 +1883,7 @@ void Main::on_newAccount_triggered()
lp = KeyPair::create();
auto a = lp.address();
if (v == NoVanity ||
(v == DirectICAP && !a[0]) ||
(v == FirstTwo && a[0] == a[1]) ||
(v == FirstTwoNextTwo && a[0] == a[1] && a[2] == a[3]) ||
(v == FirstThree && a[0] == a[1] && a[1] == a[2]) ||
@ -1753,7 +1928,7 @@ void Main::on_go_triggered()
ui->net->setChecked(true);
on_net_triggered();
}
web3()->connect(Host::pocHost());
web3()->addNode(p2p::NodeId(), Host::pocHost());
}
QString Main::prettyU256(dev::u256 _n) const
@ -1835,3 +2010,9 @@ void Main::refreshWhispers()
ui->whispers->addItem(item);
}
}
void Main::dappLoaded(Dapp& _dapp)
{
QUrl url = m_dappHost->hostDapp(std::move(_dapp));
ui->webView->page()->setUrl(url);
}

17
alethzero/MainWin.h

@ -40,6 +40,7 @@
#include "Context.h"
#include "Transact.h"
#include "NatspecHandler.h"
#include "Connect.h"
namespace Ui {
class Main;
@ -54,8 +55,11 @@ namespace jsonrpc {
class HttpServer;
}
class QQuickView;
class QWebEnginePage;
class OurWebThreeStubServer;
class DappLoader;
class DappHost;
struct Dapp;
using WatchHandler = std::function<void(dev::eth::LocalisedLogEntries const&)>;
@ -99,6 +103,7 @@ public slots:
private slots:
void eval(QString const& _js);
void addConsoleMessage(QString const& _js, QString const& _s);
// Application
void on_about_triggered();
@ -172,6 +177,9 @@ private slots:
void refreshBlockChain();
void addNewId(QString _ids);
// Dapps
void dappLoaded(Dapp& _dapp); //qt does not support rvalue refs for signals
signals:
void poll();
@ -234,8 +242,6 @@ private:
QString m_privateChain;
dev::Address m_nameReg;
QNetworkAccessManager m_webCtrl;
QList<QPair<QString, QString>> m_consoleHistory;
QMutex m_logLock;
QString m_logHistory;
@ -248,4 +254,9 @@ private:
NatspecHandler m_natSpecDB;
Transact m_transact;
std::unique_ptr<DappHost> m_dappHost;
DappLoader* m_dappLoader;
QWebEnginePage* m_webPage;
Connect m_connect;
};

395
alethzero/Transact.cpp

@ -25,6 +25,7 @@
#include "Transact.h"
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <QFileDialog>
#include <QMessageBox>
#include <liblll/Compiler.h>
@ -135,7 +136,39 @@ void Transact::updateFee()
ui->total->setPalette(p);
}
string Transact::getFunctionHashes(dev::solidity::CompilerStack const& _compiler, string const& _contractName)
void Transact::on_destination_currentTextChanged(QString)
{
if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)")
if (Address a = m_context->fromString(ui->destination->currentText()))
ui->calculatedName->setText(m_context->render(a));
else
ui->calculatedName->setText("Unknown Address");
else
ui->calculatedName->setText("Create Contract");
rejigData();
// updateFee();
}
static std::string toString(TransactionException _te)
{
switch (_te)
{
case TransactionException::Unknown: return "Unknown error";
case TransactionException::InvalidSignature: return "Permanent Abort: Invalid transaction signature";
case TransactionException::InvalidNonce: return "Transient Abort: Invalid transaction nonce";
case TransactionException::NotEnoughCash: return "Transient Abort: Not enough cash to pay for transaction";
case TransactionException::OutOfGasBase: return "Permanent Abort: Not enough gas to consider transaction";
case TransactionException::BlockGasLimitReached: return "Transient Abort: Gas limit of block reached";
case TransactionException::BadInstruction: return "VM Error: Attempt to execute invalid instruction";
case TransactionException::BadJumpDestination: return "VM Error: Attempt to jump to invalid destination";
case TransactionException::OutOfGas: return "VM Error: Out of gas";
case TransactionException::OutOfStack: return "VM Error: VM stack limit reached during execution";
case TransactionException::StackUnderflow: return "VM Error: Stack underflow";
default:; return std::string();
}
}
static string getFunctionHashes(dev::solidity::CompilerStack const& _compiler, string const& _contractName)
{
string ret = "";
auto const& contract = _compiler.getContractDefinition(_contractName);
@ -150,184 +183,256 @@ string Transact::getFunctionHashes(dev::solidity::CompilerStack const& _compiler
return ret;
}
void Transact::on_destination_currentTextChanged(QString)
{
if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)")
if (Address a = m_context->fromString(ui->destination->currentText()))
ui->calculatedName->setText(m_context->render(a));
else
ui->calculatedName->setText("Unknown Address");
else
ui->calculatedName->setText("Create Contract");
rejigData();
// updateFee();
}
void Transact::rejigData()
static tuple<vector<string>, bytes, string> userInputToCode(string const& _user, bool _opt)
{
if (isCreation())
string lll;
string solidity;
bytes data;
vector<string> errors;
if (_user.find_first_not_of("1234567890abcdefABCDEF\n\t ") == string::npos && _user.size() % 2 == 0)
{
string src = ui->data->toPlainText().toStdString();
vector<string> errors;
QString lll;
QString solidity;
if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0)
m_data = fromHex(src);
else if (sourceIsSolidity(src))
std::string u = _user;
boost::replace_all_copy(u, "\n", "");
boost::replace_all_copy(u, "\t", "");
boost::replace_all_copy(u, " ", "");
data = fromHex(u);
}
else if (sourceIsSolidity(_user))
{
dev::solidity::CompilerStack compiler(true);
try
{
dev::solidity::CompilerStack compiler;
try
{
// compiler.addSources(dev::solidity::StandardSources);
m_data = compiler.compile(src, ui->optimize->isChecked());
solidity = "<h4>Solidity</h4>";
solidity += "<pre>var " + QString::fromStdString(compiler.defaultContractName()) + " = web3.eth.contractFromAbi(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + ");</pre>";
solidity += "<pre>" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "</pre>";
solidity += "<pre>" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "</pre>";
}
catch (dev::Exception const& exception)
{
ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
solidity = "<h4>Solidity</h4><pre>" + QString::fromStdString(error.str()).toHtmlEscaped() + "</pre>";
}
catch (...)
{
solidity = "<h4>Solidity</h4><pre>Uncaught exception.</pre>";
}
data = compiler.compile(_user, _opt);
solidity = "<h4>Solidity</h4>";
solidity += "<pre>var " + compiler.defaultContractName() + " = web3.eth.contract(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped().toStdString() + ");</pre>";
solidity += "<pre>" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped().toStdString() + "</pre>";
solidity += "<pre>" + QString::fromStdString(getFunctionHashes(compiler, "")).toHtmlEscaped().toStdString() + "</pre>";
}
catch (dev::Exception const& exception)
{
ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
errors.push_back("Solidity: " + error.str());
}
catch (...)
{
errors.push_back("Solidity: Uncaught exception");
}
}
#ifndef _MSC_VER
else if (sourceIsSerpent(src))
else if (sourceIsSerpent(_user))
{
try
{
try
{
m_data = dev::asBytes(::compile(src));
for (auto& i: errors)
i = "(LLL " + i + ")";
}
catch (string const& err)
{
errors.push_back("Serpent " + err);
}
data = dev::asBytes(::compile(_user));
}
catch (string const& err)
{
errors.push_back("Serpent " + err);
}
}
#endif
else
{
data = compileLLL(_user, _opt, &errors);
if (errors.empty())
{
auto asmcode = compileLLLToAsm(_user, _opt);
lll = "<h4>LLL</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped().toStdString() + "</pre>";
}
}
return make_tuple(errors, data, lll + solidity);
}
string Transact::natspecNotice(Address _to, bytes const& _data)
{
if (ethereum()->codeAt(_to, PendingBlock).size())
{
string userNotice = m_natSpecDB->getUserNotice(ethereum()->postState().codeHash(_to), _data);
if (userNotice.empty())
return "Destination contract unknown.";
else
{
m_data = compileLLL(src, ui->optimize->isChecked(), &errors);
if (errors.empty())
{
auto asmcode = compileLLLToAsm(src, false);
lll = "<h4>Pre</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>";
if (ui->optimize->isChecked())
{
asmcode = compileLLLToAsm(src, true);
lll = "<h4>Opt</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>" + lll;
}
}
NatspecExpressionEvaluator evaluator;
return evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString();
}
QString errs;
}
else
return "Destination not a contract.";
}
void Transact::rejigData()
{
if (!ethereum())
return;
// Determine how much balance we have to play with...
auto s = findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
m_allGood = true;
QString htmlInfo;
auto bail = [&](QString he) {
m_allGood = false;
ui->send->setEnabled(false);
ui->code->setHtml(he + htmlInfo);
};
// Determine m_info.
if (isCreation())
{
string info;
vector<string> errors;
tie(errors, m_data, info) = userInputToCode(ui->data->toPlainText().toStdString(), ui->optimize->isChecked());
if (errors.size())
{
errs = "<h4>Errors</h4>";
// Errors determining transaction data (i.e. init code). Bail.
QString htmlErrors;
for (auto const& i: errors)
errs.append("<div style=\"border-left: 6px solid #c00; margin-top: 2px\">" + QString::fromStdString(i).toHtmlEscaped() + "</div>");
htmlErrors.append("<div class=\"error\"><span class=\"icon\">ERROR</span> " + QString::fromStdString(i).toHtmlEscaped() + "</div>");
bail(htmlErrors);
return;
}
ui->code->setHtml(errs + lll + solidity + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped() + "<h4>Hex</h4>" Div(Mono) + QString::fromStdString(toHex(m_data)) + "</div>");
ui->gas->setMinimum((qint64)Interface::txGas(m_data, 0));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
htmlInfo = QString::fromStdString(info) + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped();
}
else
{
m_data = parseData(ui->data->toPlainText().toStdString());
auto to = m_context->fromString(ui->destination->currentText());
QString natspec;
if (ethereum()->codeAt(to, 0).size())
{
string userNotice = m_natSpecDB->getUserNotice(ethereum()->postState().codeHash(to), m_data);
if (userNotice.empty())
natspec = "Destination contract unknown.";
else
{
NatspecExpressionEvaluator evaluator;
natspec = evaluator.evalExpression(QString::fromStdString(userNotice));
}
ui->gas->setMinimum((qint64)Interface::txGas(m_data, 1));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
}
else
{
natspec += "Destination not a contract.";
if (ui->gas->isEnabled())
m_backupGas = ui->gas->value();
ui->gas->setValue((qint64)Interface::txGas(m_data));
ui->gas->setEnabled(false);
}
ui->code->setHtml("<h3>NatSpec</h3>" + natspec + "<h3>Dump</h3>" + QString::fromStdString(dev::memDump(m_data, 8, true)) + "<h3>Hex</h3>" + Div(Mono) + QString::fromStdString(toHex(m_data)) + "</div>");
htmlInfo = "<h4>Dump</h4>" + QString::fromStdString(dev::memDump(m_data, 8, true));
}
htmlInfo += "<h4>Hex</h4>" + QString(Div(Mono)) + QString::fromStdString(toHex(m_data)) + "</div>";
// Determine the minimum amount of gas we need to play...
qint64 baseGas = (qint64)Interface::txGas(m_data, 0);
qint64 gasNeeded = 0;
if (b < value() + baseGas * gasPrice())
{
// Not enough - bail.
bail("<div class=\"error\"><span class=\"icon\">ERROR</span> No single account contains enough for paying even the basic amount of gas required.</div>");
return;
}
else
gasNeeded = (qint64)min<bigint>(ethereum()->gasLimitRemaining(), ((b - value()) / gasPrice()));
// Dry-run execution to determine gas requirement and any execution errors
Address to;
ExecutionResult er;
if (isCreation())
er = ethereum()->create(s, value(), m_data, gasNeeded, gasPrice());
else
{
to = m_context->fromString(ui->destination->currentText());
er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice());
}
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded);
htmlInfo = QString("<div class=\"info\"><span class=\"icon\">INFO</span> Gas required: %1 total = %2 base, %3 exec [%4 refunded later]</div>").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo;
if (er.excepted != TransactionException::None)
{
bail("<div class=\"error\"><span class=\"icon\">ERROR</span> " + QString::fromStdString(toString(er.excepted)) + "</div>");
return;
}
if (er.codeDeposit == CodeDeposit::Failed)
{
bail("<div class=\"error\"><span class=\"icon\">ERROR</span> Code deposit failed due to insufficient gas; " + QString::fromStdString(toString(er.gasForDeposit)) + " GAS &lt; " + QString::fromStdString(toString(er.depositSize)) + " bytes * " + QString::fromStdString(toString(c_createDataGas)) + "GAS/byte</div>");
return;
}
// Add Natspec information
if (!isCreation())
htmlInfo = "<div class=\"info\"><span class=\"icon\">INFO</span> " + QString::fromStdString(natspecNotice(to, m_data)).toHtmlEscaped() + "</div>" + htmlInfo;
// Update gas
if (ui->gas->value() == ui->gas->minimum())
{
ui->gas->setMinimum(gasNeeded);
ui->gas->setValue(gasNeeded);
}
else
ui->gas->setMinimum(gasNeeded);
updateFee();
ui->code->setHtml(htmlInfo);
ui->send->setEnabled(m_allGood);
}
void Transact::on_send_clicked()
Secret Transact::findSecret(u256 _totalReq) const
{
u256 totalReq = value() + fee();
if (!ethereum())
return Secret();
Secret best;
u256 bestBalance = 0;
for (auto const& i: m_myKeys)
if (ethereum()->balanceAt(i.address(), 0) >= totalReq)
{
Secret s = i.secret();
if (isCreation())
{
auto b = ethereum()->balanceAt(i.address(), PendingBlock);
if (b >= _totalReq)
return i.secret();
if (b > bestBalance)
bestBalance = b, best = i.secret();
}
return best;
}
void Transact::on_send_clicked()
{
Secret s = findSecret(value() + fee());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
if (!s || b < value() + fee())
{
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
return;
}
if (isCreation())
{
// If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB
ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice());
string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src))
try
{
// If execution is a contract creation, add Natspec to
// a local Natspec LEVELDB
ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice());
string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src))
try
{
dev::solidity::CompilerStack compiler;
m_data = compiler.compile(src, ui->optimize->isChecked());
for (string const& s: compiler.getContractNames())
{
h256 contractHash = compiler.getContractCodeHash(s);
m_natSpecDB->add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NatspecUser));
}
}
catch (...)
{
}
close();
return;
dev::solidity::CompilerStack compiler(true);
m_data = compiler.compile(src, ui->optimize->isChecked());
for (string const& s: compiler.getContractNames())
{
h256 contractHash = compiler.getContractCodeHash(s);
m_natSpecDB->add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NatspecUser));
}
}
else
ethereum()->transact(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
return;
}
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
catch (...) {}
}
else
ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
close();
}
void Transact::on_debug_clicked()
{
Secret s = findSecret(value() + fee());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
if (!s || b < value() + fee())
{
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
return;
}
try
{
u256 totalReq = value() + fee();
for (auto i: m_myKeys)
if (ethereum()->balanceAt(i.address()) >= totalReq)
{
State st(ethereum()->postState());
Secret s = i.secret();
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText()), m_data, st.transactionsFrom(dev::toAddress(s)), s);
Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t);
dw.exec();
return;
}
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
State st(ethereum()->postState());
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText()), m_data, st.transactionsFrom(dev::toAddress(s)), s);
Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t);
dw.exec();
}
catch (dev::Exception const& _e)
{

16
alethzero/Transact.h

@ -57,7 +57,7 @@ private slots:
void on_cancel_clicked() { close(); }
private:
dev::eth::Client* ethereum() { return m_ethereum; }
dev::eth::Client* ethereum() const { return m_ethereum; }
void rejigData();
void updateDestination();
@ -68,15 +68,17 @@ private:
dev::u256 value() const;
dev::u256 gasPrice() const;
std::string getFunctionHashes(dev::solidity::CompilerStack const& _compiler, std::string const& _contractName = std::string());
std::string natspecNotice(dev::Address _to, dev::bytes const& _data);
dev::Secret findSecret(dev::u256 _totalReq) const;
Ui::Transact* ui;
Ui::Transact* ui = nullptr;
unsigned m_backupGas;
unsigned m_backupGas = 0;
dev::bytes m_data;
QList<dev::KeyPair> m_myKeys;
dev::eth::Client* m_ethereum;
Context* m_context;
NatSpecFace* m_natSpecDB;
dev::eth::Client* m_ethereum = nullptr;
Context* m_context = nullptr;
NatSpecFace* m_natSpecDB = nullptr;
bool m_allGood = false;
};

28
alethzero/WebPage.cpp

@ -0,0 +1,28 @@
/*
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 WebPage.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com>
* @date 2015
*/
#include "WebPage.h"
void WebPage::javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel _level, const QString& _message, int _lineNumber, const QString& _sourceID)
{
QString prefix = _level == QWebEnginePage::ErrorMessageLevel ? "error" : _level == QWebEnginePage::WarningMessageLevel ? "warning" : "";
emit consoleMessage(QString("%1(%2:%3):%4").arg(prefix).arg(_sourceID).arg(_lineNumber).arg(_message));
}

40
alethzero/WebPage.h

@ -0,0 +1,40 @@
/*
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 WebPage.h
* @author Arkadiy Paronyan arkadiy@ethdev.com>
* @date 2015
*/
#pragma once
#include <QString>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" //QtWebEngineWidgets/qwebenginecertificateerror.h:78:348: error: extra ';'
#include <QtWebEngineWidgets/QWebEnginePage>
#pragma GCC diagnostic pop
class WebPage: public QWebEnginePage
{
Q_OBJECT
public:
WebPage(QObject* _parent): QWebEnginePage(_parent) { }
signals:
void consoleMessage(QString const& _msg);
protected:
void javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel _level, const QString& _message, int _lineNumber, const QString& _sourceID) override;
};

31
cmake/EthCompilerSettings.cmake

@ -7,9 +7,17 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE")
set(ETH_SHARED 1)
if (PROFILING)
set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_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")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lprofiler")
endif ()
execute_process(
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
@ -25,6 +33,10 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG")
set(ETH_SHARED 1)
if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX")
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# enable parallel compilation
@ -34,12 +46,14 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# disable decorated name length exceeded, name was truncated (4503)
# disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests)
# declare Windows XP requirement
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501)
# undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions
add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX)
# disable empty object file warning
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
# warning LNK4099: pdb was not found with lib
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075")
# stack size 16MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
# windows likes static
set(ETH_STATIC 1)
@ -47,3 +61,14 @@ else ()
message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.")
endif ()
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
option(USE_LD_GOLD "Use GNU gold linker" ON)
if (USE_LD_GOLD)
execute_process(COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
if ("${LD_VERSION}" MATCHES "GNU gold")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
endif ()
endif ()
endif ()

60
cmake/EthDependencies.cmake

@ -30,6 +30,9 @@ if (APPLE)
set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/qt5")
endif()
find_program(CTEST_COMMAND ctest)
message(STATUS "ctest path: ${CTEST_COMMAND}")
# Dependencies must have a version number, to ensure reproducible build. The version provided here is the one that is in the extdep repository. If you use system libraries, version numbers may be different.
find_package (CryptoPP 5.6.2 EXACT REQUIRED)
@ -45,16 +48,10 @@ find_package (Jsoncpp 0.60 REQUIRED)
message(" - Jsoncpp header: ${JSONCPP_INCLUDE_DIRS}")
message(" - Jsoncpp lib : ${JSONCPP_LIBRARIES}")
# TODO the JsonRpcCpp package does not yet check for correct version number
# json-rpc-cpp support is currently not mandatory
# TODO make headless client optional
# TODO get rid of -DETH_JSONRPC
# TODO add EXACT once we commit ourselves to cmake 3.x
if (JSONRPC)
find_package (JsonRpcCpp 0.3.2)
if (NOT JSON_RPC_CPP_FOUND)
message (FATAL_ERROR "JSONRPC 0.3.2. not found")
endif()
find_package (json_rpc_cpp 0.4 REQUIRED)
message (" - json-rpc-cpp header: ${JSON_RPC_CPP_INCLUDE_DIRS}")
message (" - json-rpc-cpp lib : ${JSON_RPC_CPP_LIBRARIES}")
add_definitions(-DETH_JSONRPC)
@ -104,7 +101,7 @@ find_program(ETH_JSON_RPC_STUB jsonrpcstub)
message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}")
# do not compile GUI
if (NOT HEADLESS)
if (GUI)
# we need json rpc to build alethzero
if (NOT JSON_RPC_CPP_FOUND)
@ -114,14 +111,17 @@ if (NOT HEADLESS)
# find all of the Qt packages
# remember to use 'Qt' instead of 'QT', cause unix is case sensitive
# TODO make headless client optional
find_package (Qt5Core REQUIRED)
find_package (Qt5Gui REQUIRED)
find_package (Qt5Quick REQUIRED)
find_package (Qt5Qml REQUIRED)
find_package (Qt5Network REQUIRED)
find_package (Qt5Widgets REQUIRED)
find_package (Qt5WebEngine REQUIRED)
find_package (Qt5WebEngineWidgets REQUIRED)
set (ETH_QT_VERSION 5.4)
find_package (Qt5Core ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Gui ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Quick ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Qml ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Network ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5Widgets ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5WebEngine ${ETH_QT_VERSION} REQUIRED)
find_package (Qt5WebEngineWidgets ${ETH_QT_VERSION} REQUIRED)
# we need to find path to macdeployqt on mac
if (APPLE)
@ -134,16 +134,26 @@ if (NOT HEADLESS)
message(" - windeployqt path: ${WINDEPLOYQT_APP}")
endif()
# TODO check node && npm version
find_program(ETH_NODE node)
string(REGEX REPLACE "node" "" ETH_NODE_DIRECTORY ${ETH_NODE})
message(" - nodejs location : ${ETH_NODE}")
if (USENPM)
# TODO check node && npm version
find_program(ETH_NODE node)
string(REGEX REPLACE "node" "" ETH_NODE_DIRECTORY ${ETH_NODE})
message(" - nodejs location : ${ETH_NODE}")
find_program(ETH_NPM npm)
string(REGEX REPLACE "npm" "" ETH_NPM_DIRECTORY ${ETH_NPM})
message(" - npm location : ${ETH_NPM}")
find_program(ETH_NPM npm)
string(REGEX REPLACE "npm" "" ETH_NPM_DIRECTORY ${ETH_NPM})
message(" - npm location : ${ETH_NPM}")
if (NOT ETH_NODE)
message(FATAL_ERROR "node not found!")
endif()
if (NOT ETH_NPM)
message(FATAL_ERROR "npm not found!")
endif()
endif()
endif() #HEADLESS
endif() #GUI
# use multithreaded boost libraries, with -mt suffix
set(Boost_USE_MULTITHREADED ON)

40
cmake/EthUtils.cmake

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

29
cmake/FindJsonRpcCpp.cmake → cmake/Findjson_rpc_cpp.cmake

@ -10,6 +10,11 @@
# JSON_RPC_CPP_SERVER_LIBRARIES, the libraries needed to use json-rpc-cpp-server
# JSON_RPC_CPP_CLIENT_LIBRARIES, the libraries needed to use json-rpc-cpp-client
# JSON_RCP_CPP_FOUND, If false, do not try to use json-rpc-cpp.
# JSON_RPC_CPP_VERSION, version of library
# JSON_RPC_CPP_VERSION_MAJOR
# JSON_RPC_CPP_VERSION_MINOR
# JSON_RPC_CPP_VERSION_PATCH
# only look in default directories
find_path(
@ -90,10 +95,28 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
endif()
if (JSON_RPC_CPP_INCLUDE_DIR)
set (JSON_RPC_CPP_VERSION_HEADER "${JSON_RPC_CPP_INCLUDE_DIR}/jsonrpccpp/version.h")
if (EXISTS ${JSON_RPC_CPP_VERSION_HEADER})
file (STRINGS ${JSON_RPC_CPP_VERSION_HEADER} JSON_RPC_CPP_VERSION_MAJOR REGEX "^#define JSONRPC_CPP_MAJOR_VERSION[ \t]+[0-9]+$")
file (STRINGS ${JSON_RPC_CPP_VERSION_HEADER} JSON_RPC_CPP_VERSION_MINOR REGEX "^#define JSONRPC_CPP_MINOR_VERSION[ \t]+[0-9]+$")
file (STRINGS ${JSON_RPC_CPP_VERSION_HEADER} JSON_RPC_CPP_VERSION_PATCH REGEX "^#define JSONRPC_CPP_PATCH_VERSION[ \t]+[0-9]+$")
string (REGEX REPLACE "^#define JSONRPC_CPP_MAJOR_VERSION[ \t]+([0-9]+)" "\\1" JSON_RPC_CPP_VERSION_MAJOR ${JSON_RPC_CPP_VERSION_MAJOR})
string (REGEX REPLACE "^#define JSONRPC_CPP_MINOR_VERSION[ \t]+([0-9]+)" "\\1" JSON_RPC_CPP_VERSION_MINOR ${JSON_RPC_CPP_VERSION_MINOR})
string (REGEX REPLACE "^#define JSONRPC_CPP_PATCH_VERSION[ \t]+([0-9]+)" "\\1" JSON_RPC_CPP_VERSION_PATCH ${JSON_RPC_CPP_VERSION_PATCH})
set (JSON_RPC_CPP_VERSION ${JSON_RPC_CPP_VERSION_MAJOR}.${JSON_RPC_CPP_VERSION_MINOR}.${JSON_RPC_CPP_VERSION_PATCH})
endif()
endif()
# handle the QUIETLY and REQUIRED arguments and set JSON_RPC_CPP_FOUND to TRUE
# if all listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(json_rpc_cpp DEFAULT_MSG
JSON_RPC_CPP_COMMON_LIBRARY JSON_RPC_CPP_SERVER_LIBRARY JSON_RPC_CPP_CLIENT_LIBRARY JSON_RPC_CPP_INCLUDE_DIR)
mark_as_advanced (JSON_RPC_CPP_COMMON_LIBRARY JSON_RPC_CPP_SERVER_LIBRARY JSON_RPC_CPP_CLIENT_LIBRARY JSON_RPC_CPP_INCLUDE_DIR)
find_package_handle_standard_args(
json_rpc_cpp
REQUIRED_VARS JSON_RPC_CPP_INCLUDE_DIR JSON_RPC_CPP_COMMON_LIBRARY JSON_RPC_CPP_SERVER_LIBRARY JSON_RPC_CPP_CLIENT_LIBRARY
VERSION_VAR JSON_RPC_CPP_VERSION
)
mark_as_advanced (JSON_RPC_CPP_INCLUDE_DIR JSON_RPC_CPP_COMMON_LIBRARY JSON_RPC_CPP_SERVER_LIBRARY JSON_RPC_CPP_CLIENT_LIBRARY)

15
cmake/scripts/runtest.cmake

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

117
eth/main.cpp

@ -77,7 +77,6 @@ void interactiveHelp()
<< " setetherprice <p> Resets the ether price." << endl
<< " setpriority <p> Resets the transaction priority." << endl
<< " minestart Starts mining." << endl
<< " minestart Starts mining." << endl
<< " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl
<< " address Gives the current address." << endl
@ -88,12 +87,14 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl
#if ETH_FATDB
<< " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl
<< " setsecret <secret> Set the secret to the hex secret key." <<endl
<< " setaddress <addr> Set the coinbase (mining payout) address." <<endl
<< " exportconfig <path> Export the config (.RLP) to the path provided." <<endl
<< " importconfig <path> Import the config (.RLP) from the path provided." <<endl
#endif
<< " setsecret <secret> Set the secret to the hex secret key." << endl
<< " setaddress <addr> Set the coinbase (mining payout) address." << endl
<< " exportconfig <path> Export the config (.RLP) to the path provided." << endl
<< " importconfig <path> Import the config (.RLP) from the path provided." << endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " dumptrace <block> <index> <filename> <format> Dumps a transaction trace" << endl << "to <filename>. <format> should be one of pretty, standard, standard+." << endl
<< " dumpreceipt <block> <index> Dumps a transation receipt." << endl
@ -103,7 +104,7 @@ void interactiveHelp()
void help()
{
cout
<< "Usage eth [OPTIONS] <remote-host>" << endl
<< "Usage eth [OPTIONS]" << endl
<< "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
@ -116,20 +117,22 @@ void help()
<< " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
#if ETH_JSONRPC
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
<< " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl
#endif
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -K,--kill First kill the blockchain." << endl
<< " --listen-ip <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -l,--listen <ip> Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl
<< " -u,--public-ip <ip> Force public ip to given (default: auto)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
<< " -R,--rebuild First rebuild the blockchain from the existing database." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
@ -159,14 +162,14 @@ string credits(bool _interactive = false)
void version()
{
cout << "eth version " << dev::Version << endl;
cout << "Network protocol version: " << dev::eth::c_protocolVersion << endl;
cout << "eth network protocol version: " << dev::eth::c_protocolVersion << endl;
cout << "Client database version: " << dev::eth::c_databaseVersion << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0);
}
Address c_config = Address("ccdeac59d35627b7de09332e819d5159e7bb7250");
string pretty(h160 _a, dev::eth::State _st)
string pretty(h160 _a, dev::eth::State const& _st)
{
string ns;
h256 n;
@ -197,7 +200,9 @@ enum class NodeMode
int main(int argc, char** argv)
{
string listenIP;
unsigned short listenPort = 30303;
string publicIP;
string remoteHost;
unsigned short remotePort = 30303;
string dbPath;
@ -209,11 +214,10 @@ int main(int argc, char** argv)
#if ETH_JSONRPC
int jsonrpc = -1;
#endif
string publicIP;
bool bootstrap = false;
bool upnp = true;
bool useLocal = false;
bool forceMining = false;
WithExisting killChain = WithExisting::Trust;
bool jit = false;
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
@ -247,7 +251,9 @@ int main(int argc, char** argv)
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
if (arg == "--listen-ip" && i + 1 < argc)
listenIP = argv[++i];
else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
listenPort = (short)atoi(argv[++i]);
else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
publicIP = argv[++i];
@ -268,15 +274,16 @@ int main(int argc, char** argv)
return -1;
}
}
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill")
killChain = WithExisting::Kill;
else if (arg == "-B" || arg == "--rebuild")
killChain = WithExisting::Verify;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
{
try
{
coinbase = h160(fromHex(argv[++i], ThrowType::Throw));
coinbase = h160(fromHex(argv[++i], WhenError::Throw));
}
catch (BadHexCharacter& _e)
{
@ -289,7 +296,6 @@ int main(int argc, char** argv)
cwarn << "coinbase rejected";
break;
}
}
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc)
us = KeyPair(h256(fromHex(argv[++i])));
else if (arg == "--structured-logging-format" && i + 1 < argc)
@ -300,20 +306,24 @@ int main(int argc, char** argv)
dbPath = argv[++i];
else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
{
try {
try
{
blockFees = stof(argv[++i]);
}
catch (...) {
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
}
else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc)
{
try {
try
{
etherPrice = stof(argv[++i]);
}
catch (...) {
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
@ -364,7 +374,7 @@ int main(int argc, char** argv)
interactive = true;
#if ETH_JSONRPC
else if ((arg == "-j" || arg == "--json-rpc"))
jsonrpc = jsonrpc == -1 ? 8080 : jsonrpc;
jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc;
else if (arg == "--json-rpc-port" && i + 1 < argc)
jsonrpc = atoi(argv[++i]);
#endif
@ -401,7 +411,10 @@ int main(int argc, char** argv)
else if (arg == "-V" || arg == "--version")
version();
else
remoteHost = argv[i];
{
cerr << "Invalid argument: " << arg << endl;
exit(-1);
}
}
if (!clientName.empty())
@ -411,13 +424,13 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3(
clientImplString,
dbPath,
false,
killChain,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs,
&nodesState,
@ -434,20 +447,21 @@ int main(int argc, char** argv)
c->setAddress(coinbase);
}
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
cout << "Transaction Signer: " << us.address() << endl;
cout << "Mining Benefactor: " << coinbase << endl;
web3.startNetwork();
if (bootstrap)
web3.connect(Host::pocHost());
web3.addNode(p2p::NodeId(), Host::pocHost());
if (remoteHost.size())
web3.connect(remoteHost, remotePort);
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC
shared_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1)
{
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc));
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
@ -500,7 +514,7 @@ int main(int argc, char** argv)
string addr;
unsigned port;
iss >> addr >> port;
web3.connect(addr, (short)port);
web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort));
}
else if (cmd == "netstop")
{
@ -572,8 +586,8 @@ int main(int argc, char** argv)
else if (cmd == "jsonstart")
{
if (jsonrpc < 0)
jsonrpc = 8080;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc));
jsonrpc = SensibleHttpPort;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
@ -659,7 +673,7 @@ int main(int argc, char** argv)
{
Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(hexAddr));
c->transact(secret, amount, dest, data, gas, gasPrice);
c->submitTransaction(secret, amount, dest, data, gas, gasPrice);
}
catch (BadHexCharacter& _e)
{
@ -673,14 +687,15 @@ int main(int argc, char** argv)
}
}
else
cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
}
#if ETH_FATDB
else if (c && cmd == "listcontracts")
{
auto acs =c->addresses();
string ss;
for (auto const& i: acs)
if ( c->codeAt(i, 0).size())
if ( c->codeAt(i, PendingBlock).size())
{
ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl;
@ -691,12 +706,13 @@ int main(int argc, char** argv)
auto acs =c->addresses();
string ss;
for (auto const& i: acs)
if ( c->codeAt(i, 0).empty())
if ( c->codeAt(i, PendingBlock).empty())
{
ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl;
}
}
#endif
else if (c && cmd == "send")
{
if (iss.peek() != -1)
@ -720,8 +736,8 @@ int main(int argc, char** argv)
u256 minGas = (u256)Client::txGas(bytes(), 0);
try
{
Address dest = h160(fromHex(hexAddr, ThrowType::Throw));
c->transact(us.secret(), amount, dest, bytes(), minGas);
Address dest = h160(fromHex(hexAddr, WhenError::Throw));
c->submitTransaction(us.secret(), amount, dest, bytes(), minGas);
}
catch (BadHexCharacter& _e)
{
@ -764,7 +780,7 @@ int main(int argc, char** argv)
stringstream ssc;
try
{
init = fromHex(sinit, ThrowType::Throw);
init = fromHex(sinit, WhenError::Throw);
}
catch (BadHexCharacter& _e)
{
@ -790,7 +806,7 @@ int main(int argc, char** argv)
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else
c->transact(us.secret(), endowment, init, gas, gasPrice);
c->submitTransaction(us.secret(), endowment, init, gas, gasPrice);
}
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
@ -822,11 +838,8 @@ int main(int argc, char** argv)
Executive e(state, c->blockChain(), 0);
Transaction t = state.pending()[index];
state = state.fromPending(index);
bytes r = t.rlp();
try
{
e.setup(&r);
OnOpFunc oof;
if (format == "pretty")
oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
@ -859,7 +872,9 @@ int main(int argc, char** argv)
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
e.go(oof);
e.initialize(t);
if (!e.execute())
e.go(oof);
e.finalize();
}
catch(Exception const& _e)
@ -883,10 +898,10 @@ int main(int argc, char** argv)
try
{
auto storage =c->storageAt(h, 0);
auto storage =c->storageAt(h, PendingBlock);
for (auto const& i: storage)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
s << endl << disassemble( c->codeAt(h, 0)) << endl;
s << endl << disassemble( c->codeAt(h, PendingBlock)) << endl;
string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs;
@ -925,7 +940,7 @@ int main(int argc, char** argv)
{
try
{
coinbase = h160(fromHex(hexAddr, ThrowType::Throw));
coinbase = h160(fromHex(hexAddr, WhenError::Throw));
}
catch (BadHexCharacter& _e)
{

35
ethrpctest/CMakeLists.txt

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

129
ethrpctest/CommandLineInterface.cpp

@ -0,0 +1,129 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CommandLineInterface.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <string>
#include <iostream>
#include <fstream>
#include <csignal>
#include <thread>
#include <boost/filesystem.hpp>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <libtestutils/Common.h>
#include <libtestutils/BlockChainLoader.h>
#include <libtestutils/FixedClient.h>
#include <libtestutils/FixedWebThreeServer.h>
#include "CommandLineInterface.h"
#include "BuildInfo.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
namespace po = boost::program_options;
bool CommandLineInterface::parseArguments(int argc, char** argv)
{
// Declare the supported options.
po::options_description desc("Allowed options");
desc.add_options()
("help", "Show help message and exit")
("json", po::value<vector<string>>()->required(), "input file")
("test", po::value<vector<string>>()->required(), "test case name");
// All positional options should be interpreted as input files
po::positional_options_description p;
// parse the compiler arguments
try
{
po::store(po::command_line_parser(argc, argv).options(desc).positional(p).allow_unregistered().run(), m_args);
if (m_args.count("help"))
{
cout << desc;
return false;
}
po::notify(m_args);
}
catch (po::error const& _exception)
{
cout << _exception.what() << endl;
return false;
}
return true;
}
bool CommandLineInterface::processInput()
{
string infile = m_args["json"].as<vector<string>>()[0];
auto path = boost::filesystem::path(infile);
if (!boost::filesystem::exists(path))
{
cout << "Non existant input file \"" << infile << "\"" << endl;
return false;
}
string test = m_args["test"].as<vector<string>>()[0];
Json::Value j = dev::test::loadJsonFromFile(path.string());
if (j[test].empty())
{
cout << "Non existant test case \"" << infile << "\"" << endl;
return false;
}
if (!j[test].isObject())
{
cout << "Incorrect JSON file \"" << infile << "\"" << endl;
return false;
}
m_json = j[test];
return true;
}
bool g_exit = false;
void sighandler(int)
{
g_exit = true;
}
void CommandLineInterface::actOnInput()
{
BlockChainLoader bcl(m_json);
FixedClient client(bcl.bc(), bcl.state());
unique_ptr<FixedWebThreeServer> jsonrpcServer;
auto server = new jsonrpc::HttpServer(8080, "", "", 2);
jsonrpcServer.reset(new FixedWebThreeServer(*server, {}, &client));
jsonrpcServer->StartListening();
signal(SIGABRT, &sighandler);
signal(SIGTERM, &sighandler);
signal(SIGINT, &sighandler);
while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
}

46
ethrpctest/CommandLineInterface.h

@ -0,0 +1,46 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** CommandLineInterface.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <json/json.h>
#include <boost/program_options.hpp>
class CommandLineInterface
{
public:
CommandLineInterface() {}
/// Parse command line arguments and return false if we should not continue
bool parseArguments(int argc, char** argv);
/// Parse input file and check if test exists
bool processInput();
/// Start FixedJsonRpcServer
void actOnInput();
private:
/// Compiler arguments variable map
boost::program_options::variables_map m_args;
/// loaded json test case
Json::Value m_json;
};

34
ethrpctest/main.cpp

@ -0,0 +1,34 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** main.cpp
* @author Marek Kotewicz <c@ethdev.com>
* @date 2015
*/
#include "CommandLineInterface.h"
int main(int argc, char** argv)
{
CommandLineInterface cli;
if (!cli.parseArguments(argc, argv))
return 1;
if (!cli.processInput())
return 1;
cli.actOnInput();
return 0;
}

4
evmjit/CMakeLists.txt

@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF)
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-unknown-pragmas")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas")
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
@ -22,7 +22,7 @@ if(LLVM_DIR OR APPLE) # local LLVM build
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
add_definitions(${LLVM_DEFINITIONS})
# TODO: bitwriter is needed only for evmcc
llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter)
llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter ipo)
else()
# Workaround for Ubuntu broken LLVM package
message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake")

3
evmjit/libevmjit-cpp/CMakeLists.txt

@ -4,8 +4,9 @@ set(TARGET_NAME evmjit-cpp)
find_package(Boost REQUIRED)
set(SOURCES
Env.cpp
Env.cpp
JitVM.cpp JitVM.h
Utils.h
)
source_group("" FILES ${SOURCES})

39
evmjit/libevmjit-cpp/Env.cpp

@ -52,7 +52,6 @@ extern "C"
auto endowment = llvm2eth(*_endowment);
if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024)
{
_env->subBalance(endowment);
u256 gas = *io_gas;
h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight);
*io_gas = static_cast<int64_t>(gas);
@ -62,23 +61,37 @@ extern "C"
*o_address = {};
}
EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress)
EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, int64_t _callGas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress)
{
auto value = llvm2eth(*_value);
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
auto receiveAddress = right160(*_receiveAddress);
auto codeAddress = right160(*_codeAddress);
const auto isCall = receiveAddress == codeAddress; // OPT: The same address pointer can be used if not CODECALL
*io_gas -= _callGas;
if (*io_gas < 0)
return false;
if (isCall && !_env->exists(receiveAddress))
*io_gas -= static_cast<int64_t>(c_callNewAccountGas); // no underflow, *io_gas non-negative before
if (value > 0) // value transfer
{
_env->subBalance(value);
auto receiveAddress = right160(*_receiveAddress);
auto inRef = bytesConstRef{_inBeg, _inSize};
auto outRef = bytesRef{_outBeg, _outSize};
auto codeAddress = right160(*_codeAddress);
u256 gas = *io_gas;
auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress);
*io_gas = static_cast<int64_t>(gas);
return ret;
/*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible");
*io_gas -= static_cast<int64_t>(c_callValueTransferGas); // no underflow
_callGas += static_cast<int64_t>(c_callStipend); // overflow possibility, but in the same time *io_gas < 0
}
return false;
if (*io_gas < 0)
return false;
auto ret = false;
auto callGas = u256{_callGas};
if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress);
*io_gas += static_cast<int64_t>(callGas); // it is never more than initial _callGas
return ret;
}
EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash)

4
evmjit/libevmjit-cpp/JitVM.cpp

@ -69,8 +69,8 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
BOOST_THROW_EXCEPTION(BadJumpDestination());
case ReturnCode::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas());
case ReturnCode::StackTooSmall:
BOOST_THROW_EXCEPTION(StackTooSmall());
case ReturnCode::StackUnderflow:
BOOST_THROW_EXCEPTION(StackUnderflow());
case ReturnCode::BadInstruction:
BOOST_THROW_EXCEPTION(BadInstruction());
case ReturnCode::LinkerWorkaround: // never happens

135
evmjit/libevmjit/Arith256.cpp

@ -9,6 +9,7 @@
#include "Type.h"
#include "Endianness.h"
#include "Utils.h"
namespace dev
{
@ -38,6 +39,8 @@ llvm::Function* Arith256::getMulFunc()
{
llvm::Type* argTypes[] = {Type::Word, Type::Word};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule());
func->setDoesNotThrow();
func->setDoesNotAccessMemory();
auto x = &func->getArgumentList().front();
x->setName("x");
@ -50,12 +53,16 @@ llvm::Function* Arith256::getMulFunc()
auto i64 = Type::Size;
auto i128 = m_builder.getIntNTy(128);
auto i256 = Type::Word;
auto c64 = Constant::get(64);
auto c128 = Constant::get(128);
auto c192 = Constant::get(192);
auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo");
auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo");
auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64);
auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64);
auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128);
auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128);
auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, c64), i64);
auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, c64), i64);
auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, c128), i128);
auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, c128), i128);
auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128));
auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128));
@ -67,13 +74,13 @@ llvm::Function* Arith256::getMulFunc()
auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128));
auto p = m_builder.CreateZExt(t1, i256);
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192)));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), c64));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), c128));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), c64));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), c128));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), c192));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), c128));
p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), c192));
m_builder.CreateRet(p);
}
return func;
@ -87,6 +94,8 @@ llvm::Function* Arith256::getMul512Func()
auto i512 = m_builder.getIntNTy(512);
llvm::Type* argTypes[] = {Type::Word, Type::Word};
func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule());
func->setDoesNotThrow();
func->setDoesNotAccessMemory();
auto x = &func->getArgumentList().front();
x->setName("x");
@ -130,6 +139,8 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type)
auto retType = llvm::StructType::get(m_builder.getContext(), llvm::ArrayRef<llvm::Type*>{argTypes});
auto funcName = _type == Type::Word ? "div" : "div512";
func = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, funcName, getModule());
func->setDoesNotThrow();
func->setDoesNotAccessMemory();
auto zero = llvm::ConstantInt::get(_type, 0);
auto one = llvm::ConstantInt::get(_type, 1);
@ -221,6 +232,8 @@ llvm::Function* Arith256::getExpFunc()
{
llvm::Type* argTypes[] = {Type::Word, Type::Word};
m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule());
m_exp->setDoesNotThrow();
m_exp->setDoesNotAccessMemory();
auto base = &m_exp->getArgumentList().front();
base->setName("base");
@ -289,6 +302,8 @@ llvm::Function* Arith256::getAddModFunc()
auto i512Ty = m_builder.getIntNTy(512);
llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word};
m_addmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "addmod", getModule());
m_addmod->setDoesNotThrow();
m_addmod->setDoesNotAccessMemory();
auto x = &m_addmod->getArgumentList().front();
x->setName("x");
@ -318,6 +333,8 @@ llvm::Function* Arith256::getMulModFunc()
{
llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word};
m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule());
m_mulmod->setDoesNotThrow();
m_mulmod->setDoesNotAccessMemory();
auto i512Ty = m_builder.getIntNTy(512);
auto x = &m_mulmod->getArgumentList().front();
@ -343,18 +360,51 @@ llvm::Function* Arith256::getMulModFunc()
llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2)
{
if (auto c1 = llvm::dyn_cast<llvm::ConstantInt>(_arg1))
{
if (auto c2 = llvm::dyn_cast<llvm::ConstantInt>(_arg2))
return Constant::get(c1->getValue() * c2->getValue());
}
return createCall(getMulFunc(), {_arg1, _arg2});
}
std::pair<llvm::Value*, llvm::Value*> Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2)
{
auto div = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 0, "div");
auto mod = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 1, "mod");
// FIXME: Disabled because of llvm::APInt::urem bug
// if (auto c1 = llvm::dyn_cast<llvm::ConstantInt>(_arg1))
// {
// if (auto c2 = llvm::dyn_cast<llvm::ConstantInt>(_arg2))
// {
// if (!c2->getValue())
// return std::make_pair(Constant::get(0), Constant::get(0));
// auto div = Constant::get(c1->getValue().udiv(c2->getValue()));
// auto mod = Constant::get(c1->getValue().urem(c2->getValue()));
// return std::make_pair(div, mod);
// }
// }
auto r = createCall(getDivFunc(Type::Word), {_arg1, _arg2});
auto div = m_builder.CreateExtractValue(r, 0, "div");
auto mod = m_builder.CreateExtractValue(r, 1, "mod");
return std::make_pair(div, mod);
}
std::pair<llvm::Value*, llvm::Value*> Arith256::sdiv(llvm::Value* _x, llvm::Value* _y)
{
// FIXME: Disabled because of llvm::APInt::urem bug
// if (auto c1 = llvm::dyn_cast<llvm::ConstantInt>(_x))
// {
// if (auto c2 = llvm::dyn_cast<llvm::ConstantInt>(_y))
// {
// if (!c2->getValue())
// return std::make_pair(Constant::get(0), Constant::get(0));
// auto div = Constant::get(c1->getValue().sdiv(c2->getValue()));
// auto mod = Constant::get(c1->getValue().srem(c2->getValue()));
// return std::make_pair(div, mod);
// }
// }
auto xIsNeg = m_builder.CreateICmpSLT(_x, Constant::get(0));
auto xNeg = m_builder.CreateSub(Constant::get(0), _x);
auto xAbs = m_builder.CreateSelect(xIsNeg, xNeg, _x);
@ -378,16 +428,73 @@ std::pair<llvm::Value*, llvm::Value*> Arith256::sdiv(llvm::Value* _x, llvm::Valu
llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2)
{
// while (e != 0) {
// if (e % 2 == 1)
// r *= b;
// b *= b;
// e /= 2;
// }
if (auto c1 = llvm::dyn_cast<llvm::ConstantInt>(_arg1))
{
if (auto c2 = llvm::dyn_cast<llvm::ConstantInt>(_arg2))
{
auto b = c1->getValue();
auto e = c2->getValue();
auto r = llvm::APInt{256, 1};
while (e != 0)
{
if (e[0])
r *= b;
b *= b;
e = e.lshr(1);
}
return Constant::get(r);
}
}
return createCall(getExpFunc(), {_arg1, _arg2});
}
llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
// FIXME: Disabled because of llvm::APInt::urem bug
// if (auto c1 = llvm::dyn_cast<llvm::ConstantInt>(_arg1))
// {
// if (auto c2 = llvm::dyn_cast<llvm::ConstantInt>(_arg2))
// {
// if (auto c3 = llvm::dyn_cast<llvm::ConstantInt>(_arg3))
// {
// if (!c3->getValue())
// return Constant::get(0);
// auto s = c1->getValue().zext(256+64) + c2->getValue().zext(256+64);
// auto r = s.urem(c3->getValue().zext(256+64)).trunc(256);
// return Constant::get(r);
// }
// }
// }
return createCall(getAddModFunc(), {_arg1, _arg2, _arg3});
}
llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3)
{
// FIXME: Disabled because of llvm::APInt::urem bug
// if (auto c1 = llvm::dyn_cast<llvm::ConstantInt>(_arg1))
// {
// if (auto c2 = llvm::dyn_cast<llvm::ConstantInt>(_arg2))
// {
// if (auto c3 = llvm::dyn_cast<llvm::ConstantInt>(_arg3))
// {
// if (!c3->getValue())
// return Constant::get(0);
// auto p = c1->getValue().zext(512) * c2->getValue().zext(512);
// auto r = p.urem(c3->getValue().zext(512)).trunc(256);
// return Constant::get(r);
// }
// }
// }
return createCall(getMulModFunc(), {_arg1, _arg2, _arg3});
}
@ -400,7 +507,7 @@ extern "C"
{
EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z)
{
std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a
DLOG(JIT) << "DEBUG " << std::dec << z << ": " //<< d << c << b << a
<< " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n";
}
}

320
evmjit/libevmjit/Array.cpp

@ -0,0 +1,320 @@
#include "Array.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/IR/Function.h>
#include "preprocessor/llvm_includes_end.h"
#include "RuntimeManager.h"
#include "Runtime.h"
#include "Utils.h"
#include <set> // DEBUG only
namespace dev
{
namespace eth
{
namespace jit
{
static const auto c_reallocStep = 1;
static const auto c_reallocMultipier = 2;
llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args, llvm::Twine const& _name)
{
if (!m_func)
m_func = m_creator();
return _builder.CreateCall(m_func, {_args.begin(), _args.size()}, _name);
}
llvm::Function* Array::createArrayPushFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Word};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto value = arrayPtr->getNextNode();
value->setName("value");
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func);
auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func);
auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func);
m_builder.SetInsertPoint(entryBB);
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr");
auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto size = m_builder.CreateLoad(sizePtr, "size");
auto cap = m_builder.CreateLoad(capPtr, "cap");
auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq");
m_builder.CreateCondBr(reallocReq, reallocBB, pushBB);
m_builder.SetInsertPoint(reallocBB);
auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap");
//newCap = m_builder.CreateNUWMul(newCap, m_builder.getInt64(c_reallocMultipier));
auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32
auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes");
auto newBytes = m_reallocFunc.call(m_builder, {bytes, reallocSize}, "newBytes");
auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData");
m_builder.CreateStore(newData, dataPtr);
m_builder.CreateStore(newCap, capPtr);
m_builder.CreateBr(pushBB);
m_builder.SetInsertPoint(pushBB);
auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi");
dataPhi->addIncoming(data, entryBB);
dataPhi->addIncoming(newData, reallocBB);
auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr");
m_builder.CreateStore(value, newElemPtr);
auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize");
m_builder.CreateStore(newSize, sizePtr);
m_builder.CreateRetVoid();
return func;
}
llvm::Function* Array::createArraySetFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size, Type::Word};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.set", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto index = arrayPtr->getNextNode();
index->setName("index");
auto value = index->getNextNode();
value->setName("value");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
m_builder.CreateStore(value, valuePtr);
m_builder.CreateRetVoid();
return func;
}
llvm::Function* Array::createArrayGetFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "array.get", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto index = arrayPtr->getNextNode();
index->setName("index");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
auto value = m_builder.CreateLoad(valuePtr, "value");
m_builder.CreateRet(value);
return func;
}
llvm::Function* Array::createGetPtrFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::PrivateLinkage, "array.getPtr", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto index = arrayPtr->getNextNode();
index->setName("index");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto bytePtr = m_builder.CreateGEP(data, index, "bytePtr");
auto wordPtr = m_builder.CreateBitCast(bytePtr, Type::WordPtr, "wordPtr");
m_builder.CreateRet(wordPtr);
return func;
}
llvm::Function* Array::createFreeFunc()
{
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "ext_free", getModule());
freeFunc->setDoesNotThrow();
freeFunc->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem");
m_builder.CreateCall(freeFunc, mem);
m_builder.CreateRetVoid();
return func;
}
llvm::Function* Array::getReallocFunc()
{
if (auto func = getModule()->getFunction("ext_realloc"))
return func;
llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size};
auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule());
reallocFunc->setDoesNotThrow();
reallocFunc->setDoesNotAlias(0);
reallocFunc->setDoesNotCapture(1);
return reallocFunc;
}
llvm::Function* Array::createExtendFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.extend", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto newSize = arrayPtr->getNextNode();
newSize->setName("newSize");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array
auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr");
auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto size = m_builder.CreateLoad(sizePtr, "size");
auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize");
auto newData = m_reallocFunc.call(m_builder, {data, newSize}, "newData"); // TODO: Check realloc result for null
auto extPtr = m_builder.CreateGEP(newData, size, "extPtr");
m_builder.CreateMemSet(extPtr, m_builder.getInt8(0), extSize, 16);
m_builder.CreateStore(newData, dataPtr);
m_builder.CreateStore(newSize, sizePtr);
m_builder.CreateStore(newSize, capPtr);
m_builder.CreateRetVoid();
return func;
}
llvm::Type* Array::getType()
{
llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size};
static auto arrayTy = llvm::StructType::create(elementTys, "Array");
return arrayTy;
}
Array::Array(llvm::IRBuilder<>& _builder, char const* _name) :
CompilerHelper(_builder),
m_pushFunc([this](){ return createArrayPushFunc(); }),
m_setFunc([this](){ return createArraySetFunc(); }),
m_getFunc([this](){ return createArrayGetFunc(); }),
m_freeFunc([this](){ return createFreeFunc(); })
{
m_array = m_builder.CreateAlloca(getType(), nullptr, _name);
m_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array);
}
Array::Array(llvm::IRBuilder<>& _builder, llvm::Value* _array) :
CompilerHelper(_builder),
m_array(_array),
m_pushFunc([this](){ return createArrayPushFunc(); }),
m_setFunc([this](){ return createArraySetFunc(); }),
m_getFunc([this](){ return createArrayGetFunc(); }),
m_freeFunc([this](){ return createFreeFunc(); })
{
m_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array);
}
void Array::pop(llvm::Value* _count)
{
auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr");
auto size = m_builder.CreateLoad(sizePtr, "size");
auto newSize = m_builder.CreateNUWSub(size, _count, "newSize");
m_builder.CreateStore(newSize, sizePtr);
}
llvm::Value* Array::size(llvm::Value* _array)
{
auto sizePtr = m_builder.CreateStructGEP(_array ? _array : m_array, 1, "sizePtr");
return m_builder.CreateLoad(sizePtr, "array.size");
}
void Array::extend(llvm::Value* _arrayPtr, llvm::Value* _size)
{
assert(_arrayPtr->getType() == m_array->getType());
assert(_size->getType() == Type::Size);
m_extendFunc.call(m_builder, {_arrayPtr, _size});
}
}
}
}
namespace
{
struct AllocatedMemoryWatchdog
{
std::set<void*> allocatedMemory;
~AllocatedMemoryWatchdog()
{
if (!allocatedMemory.empty())
{
DLOG(mem) << allocatedMemory.size() << " MEM LEAKS!\n";
for (auto&& leak : allocatedMemory)
DLOG(mem) << "\t" << leak << "\n";
}
}
};
AllocatedMemoryWatchdog watchdog;
}
extern "C"
{
using namespace dev::eth::jit;
EXPORT void* ext_realloc(void* _data, size_t _size) noexcept
{
//std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl;
auto newData = std::realloc(_data, _size);
if (_data != newData)
{
DLOG(mem) << "REALLOC: " << newData << " <- " << _data << " [" << _size << "]\n";
watchdog.allocatedMemory.erase(_data);
watchdog.allocatedMemory.insert(newData);
}
return newData;
}
EXPORT void ext_free(void* _data) noexcept
{
std::free(_data);
if (_data)
{
DLOG(mem) << "FREE : " << _data << "\n";
watchdog.allocatedMemory.erase(_data);
}
}
} // extern "C"

74
evmjit/libevmjit/Array.h

@ -0,0 +1,74 @@
#pragma once
#include <functional>
#include "CompilerHelper.h"
namespace dev
{
namespace eth
{
namespace jit
{
class LazyFunction
{
public:
using Creator = std::function<llvm::Function*()>;
LazyFunction(Creator _creator) :
m_creator(_creator)
{}
llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args, llvm::Twine const& _name = "");
private:
llvm::Function* m_func = nullptr;
Creator m_creator;
};
class Array : public CompilerHelper
{
public:
Array(llvm::IRBuilder<>& _builder, char const* _name);
Array(llvm::IRBuilder<>& _builder, llvm::Value* _array);
void push(llvm::Value* _value) { m_pushFunc.call(m_builder, {m_array, _value}); }
void set(llvm::Value* _index, llvm::Value* _value) { m_setFunc.call(m_builder, {m_array, _index, _value}); }
llvm::Value* get(llvm::Value* _index) { return m_getFunc.call(m_builder, {m_array, _index}); }
void pop(llvm::Value* _count);
llvm::Value* size(llvm::Value* _array = nullptr);
void free() { m_freeFunc.call(m_builder, {m_array}); }
void extend(llvm::Value* _arrayPtr, llvm::Value* _size);
llvm::Value* getPtr(llvm::Value* _arrayPtr, llvm::Value* _index) { return m_getPtrFunc.call(m_builder, {_arrayPtr, _index}); }
llvm::Value* getPointerTo() const { return m_array; }
static llvm::Type* getType();
private:
llvm::Value* m_array = nullptr;
llvm::Function* createArrayPushFunc();
llvm::Function* createArraySetFunc();
llvm::Function* createArrayGetFunc();
llvm::Function* createGetPtrFunc();
llvm::Function* createFreeFunc();
llvm::Function* createExtendFunc();
llvm::Function* getReallocFunc();
LazyFunction m_pushFunc = {[this](){ return createArrayPushFunc(); }}; // TODO: If works on MSVC, remove form initialization list
LazyFunction m_setFunc;
LazyFunction m_getPtrFunc = {[this](){ return createGetPtrFunc(); }};
LazyFunction m_getFunc;
LazyFunction m_freeFunc;
LazyFunction m_extendFunc = {[this](){ return createExtendFunc(); }};
LazyFunction m_reallocFunc = {[this](){ return getReallocFunc(); }};
};
}
}
}

66
evmjit/libevmjit/BasicBlock.cpp

@ -11,6 +11,7 @@
#include "preprocessor/llvm_includes_end.h"
#include "Type.h"
#include "Utils.h"
namespace dev
{
@ -48,6 +49,7 @@ void BasicBlock::LocalStack::push(llvm::Value* _value)
assert(_value->getType() == Type::Word);
m_bblock.m_currentStack.push_back(_value);
m_bblock.m_tosOffset += 1;
m_maxSize = std::max(m_maxSize, m_bblock.m_currentStack.size());
}
llvm::Value* BasicBlock::LocalStack::pop()
@ -136,32 +138,34 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack)
{
auto blockTerminator = m_llvmBB->getTerminator();
assert(blockTerminator != nullptr);
m_builder.SetInsertPoint(blockTerminator);
if (blockTerminator->getOpcode() != llvm::Instruction::Ret)
{
// Not needed in case of ret instruction. Ret also invalidates the stack.
m_builder.SetInsertPoint(blockTerminator);
auto currIter = m_currentStack.begin();
auto endIter = m_currentStack.end();
auto currIter = m_currentStack.begin();
auto endIter = m_currentStack.end();
// Update (emit set()) changed values
for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset;
currIter < endIter && idx >= 0;
++currIter, --idx)
{
assert(static_cast<size_t>(idx) < m_initialStack.size());
if (*currIter != m_initialStack[idx]) // value needs update
_evmStack.set(static_cast<size_t>(idx), *currIter);
}
// Update (emit set()) changed values
for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset;
currIter < endIter && idx >= 0;
++currIter, --idx)
{
assert(static_cast<size_t>(idx) < m_initialStack.size());
if (*currIter != m_initialStack[idx]) // value needs update
_evmStack.set(static_cast<size_t>(idx), *currIter);
}
if (m_tosOffset < 0)
{
// Pop values
_evmStack.pop(static_cast<size_t>(-m_tosOffset));
}
if (m_tosOffset < 0)
_evmStack.pop(static_cast<size_t>(-m_tosOffset));
// Push new values
for (; currIter < endIter; ++currIter)
{
assert(*currIter != nullptr);
_evmStack.push(*currIter);
// Push new values
for (; currIter < endIter; ++currIter)
{
assert(*currIter != nullptr);
_evmStack.push(*currIter);
}
}
// Emit get() for all (used) values from the initial stack
@ -233,7 +237,7 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt)
{
auto predInfoEntry = cfg.find(*predIt);
if (predInfoEntry != cfg.end())
if (predInfoEntry != cfg.end()) // FIXME: It is wrong - will skip entry block
info.predecessors.push_back(&predInfoEntry->second);
}
}
@ -242,13 +246,12 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
bool valuesChanged = true;
while (valuesChanged)
{
if (getenv("EVMCC_DEBUG_BLOCKS"))
for (auto& pair : cfg)
{
for (auto& pair : cfg)
std::cerr << pair.second.bblock.llvm()->getName().str()
<< ": in " << pair.second.inputItems
<< ", out " << pair.second.outputItems
<< "\n";
DLOG(bb) << pair.second.bblock.llvm()->getName().str()
<< ": in " << pair.second.inputItems
<< ", out " << pair.second.outputItems
<< "\n";
}
valuesChanged = false;
@ -256,6 +259,9 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
{
auto& info = pair.second;
if (&info.bblock == basicBlocks.front())
info.inputItems = 0; // we cannot use phi nodes for first block as it is a successor of entry block
if (info.predecessors.empty())
info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false
@ -340,6 +346,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput)
{
if (val == nullptr)
out << " ?";
else if (llvm::isa<llvm::ExtractValueInst>(val))
out << " " << val->getName();
else if (llvm::isa<llvm::Instruction>(val))
out << *val;
else
@ -361,6 +369,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput)
{
if (*val == nullptr)
out << " ?";
else if (llvm::isa<llvm::ExtractValueInst>(*val))
out << " " << (*val)->getName();
else if (llvm::isa<llvm::Instruction>(*val))
out << **val;
else

4
evmjit/libevmjit/BasicBlock.h

@ -33,6 +33,9 @@ public:
/// @param _index Index of value to be swaped. Must be > 0.
void swap(size_t _index);
size_t getMaxSize() const { return m_maxSize; }
int getDiff() const { return m_bblock.m_tosOffset; }
private:
LocalStack(BasicBlock& _owner);
LocalStack(LocalStack const&) = delete;
@ -49,6 +52,7 @@ public:
private:
BasicBlock& m_bblock;
size_t m_maxSize = 0; ///< Max size reached by the stack.
};
explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);

1
evmjit/libevmjit/BuildInfo.h.in

@ -8,3 +8,4 @@
#define LLVM_VERSION "${LLVM_PACKAGE_VERSION}"
#define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}"
#define LLVM_DEBUG ${LLVM_DEBUG}

35
evmjit/libevmjit/CMakeLists.txt

@ -1,9 +1,29 @@
set(TARGET_NAME evmjit)
file(GLOB SOURCES "*.cpp")
file(GLOB HEADERS "*.h")
set(INTERFACE_HEADERS interface.h)
source_group("" FILES ${HEADERS})
set(SOURCES
Arith256.cpp Arith256.h
Array.cpp Array.h
BasicBlock.cpp BasicBlock.h
Cache.cpp Cache.h
Common.h
Compiler.cpp Compiler.h
CompilerHelper.cpp CompilerHelper.h
Endianness.cpp Endianness.h
ExecStats.cpp ExecStats.h
ExecutionEngine.cpp ExecutionEngine.h
Ext.cpp Ext.h
GasMeter.cpp GasMeter.h
Instruction.cpp Instruction.h
interface.cpp interface.h
Memory.cpp Memory.h
Optimizer.cpp Optimizer.h
Runtime.cpp Runtime.h
RuntimeData.h
RuntimeManager.cpp RuntimeManager.h
Stack.cpp Stack.h
Type.cpp Type.h
Utils.cpp Utils.h
)
source_group("" FILES ${SOURCES})
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
@ -48,11 +68,13 @@ else()
set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR})
endif()
string(COMPARE EQUAL "${LLVM_ENABLE_ASSERTIONS}" "ON" LLVM_DEBUG)
configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h)
message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})")
add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h)
add_library(${TARGET_NAME} SHARED ${SOURCES} gen/BuildInfo.gen.h)
set_target_properties(${TARGET_NAME} PROPERTIES
VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION}
FOLDER "libs")
@ -62,7 +84,4 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen)
target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS})
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin)
#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME})

112
evmjit/libevmjit/Cache.cpp

@ -1,12 +1,10 @@
#include "Cache.h"
#include <iostream>
#include <cassert>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Instructions.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_os_ostream.h>
@ -14,6 +12,7 @@
#include "ExecutionEngine.h"
#include "Utils.h"
#include "BuildInfo.gen.h"
namespace dev
{
@ -22,28 +21,84 @@ namespace eth
namespace jit
{
//#define CACHE_LOG std::cerr << "CACHE "
#define CACHE_LOG std::ostream(nullptr)
namespace
{
CacheMode g_mode;
llvm::MemoryBuffer* g_lastObject;
ExecutionEngineListener* g_listener;
static const size_t c_versionStampLength = 32;
llvm::StringRef getLibVersionStamp()
{
static auto version = llvm::SmallString<c_versionStampLength>{};
if (version.empty())
{
version = EVMJIT_VERSION_FULL;
version.resize(c_versionStampLength);
}
return version;
}
}
ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener)
ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener)
{
static ObjectCache objectCache;
g_mode = _mode;
g_listener = _listener;
return &objectCache;
}
void Cache::clear()
{
using namespace llvm::sys;
llvm::SmallString<256> cachePath;
path::system_temp_directory(false, cachePath);
path::append(cachePath, "evm_objs");
std::error_code err;
for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err))
fs::remove(it->path());
}
void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache)
{
// TODO: Cache dir should be in one place
using namespace llvm::sys;
llvm::SmallString<256> cachePath;
path::system_temp_directory(false, cachePath);
path::append(cachePath, "evm_objs");
// Disable listener
auto listener = g_listener;
g_listener = nullptr;
std::error_code err;
for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err))
{
auto name = it->path().substr(cachePath.size() + 1);
if (auto module = getObject(name))
{
DLOG(cache) << "Preload: " << name << "\n";
_ee.addModule(module.get());
module.release();
auto addr = _ee.getFunctionAddress(name);
assert(addr);
_funcCache[std::move(name)] = addr;
}
}
g_listener = listener;
}
std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
{
if (g_mode != CacheMode::on && g_mode != CacheMode::read)
return nullptr;
if (g_listener)
g_listener->stateChanged(ExecState::CacheLoad);
CACHE_LOG << id << ": search\n";
DLOG(cache) << id << ": search\n";
if (!CHECK(!g_lastObject))
g_lastObject = nullptr;
@ -51,28 +106,21 @@ std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
llvm::sys::path::system_temp_directory(false, cachePath);
llvm::sys::path::append(cachePath, "evm_objs", id);
#if defined(__GNUC__) && !defined(NDEBUG)
llvm::sys::fs::file_status st;
auto err = llvm::sys::fs::status(cachePath.str(), st);
if (err)
return nullptr;
auto mtime = st.getLastModificationTime().toEpochTime();
std::tm tm;
strptime(__DATE__ __TIME__, " %b %d %Y %H:%M:%S", &tm);
auto btime = (uint64_t)std::mktime(&tm);
if (btime > mtime)
return nullptr;
#endif
if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
{
auto& buf = r.get();
auto objVersionStamp = buf->getBufferSize() >= c_versionStampLength ? llvm::StringRef{buf->getBufferEnd() - c_versionStampLength, c_versionStampLength} : llvm::StringRef{};
if (objVersionStamp == getLibVersionStamp())
g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
else
DLOG(cache) << "Unmatched version: " << objVersionStamp.str() << ", expected " << getLibVersionStamp().str() << "\n";
}
else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
std::cerr << r.getError().message(); // TODO: Add log
DLOG(cache) << r.getError().message(); // TODO: Add warning log
if (g_lastObject) // if object found create fake module
{
CACHE_LOG << id << ": found\n";
DLOG(cache) << id << ": found\n";
auto&& context = llvm::getGlobalContext();
auto module = std::unique_ptr<llvm::Module>(new llvm::Module(id, context));
auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false);
@ -81,13 +129,17 @@ std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
bb->getInstList().push_back(new llvm::UnreachableInst{context});
return module;
}
CACHE_LOG << id << ": not found\n";
DLOG(cache) << id << ": not found\n";
return nullptr;
}
void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object)
{
// Only in "on" and "write" mode
if (g_mode != CacheMode::on && g_mode != CacheMode::write)
return;
if (g_listener)
g_listener->stateChanged(ExecState::CacheWrite);
@ -97,19 +149,19 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory
llvm::sys::path::append(cachePath, "evm_objs");
if (llvm::sys::fs::create_directory(cachePath.str()))
return; // TODO: Add log
DLOG(cache) << "Cannot create cache dir " << cachePath.str().str() << "\n";
llvm::sys::path::append(cachePath, id);
CACHE_LOG << id << ": write\n";
DLOG(cache) << id << ": write\n";
std::string error;
llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None);
cacheFile << _object->getBuffer();
cacheFile << _object->getBuffer() << getLibVersionStamp();
}
llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module)
{
CACHE_LOG << _module->getModuleIdentifier() << ": use\n";
DLOG(cache) << _module->getModuleIdentifier() << ": use\n";
auto o = g_lastObject;
g_lastObject = nullptr;
return o;

24
evmjit/libevmjit/Cache.h

@ -1,9 +1,15 @@
#pragma once
#include <memory>
#include <unordered_map>
#include <llvm/ExecutionEngine/ObjectCache.h>
namespace llvm
{
class ExecutionEngine;
}
namespace dev
{
namespace eth
@ -12,6 +18,16 @@ namespace jit
{
class ExecutionEngineListener;
enum class CacheMode
{
on,
off,
read,
write,
clear,
preload
};
class ObjectCache : public llvm::ObjectCache
{
public:
@ -29,8 +45,14 @@ public:
class Cache
{
public:
static ObjectCache* getObjectCache(ExecutionEngineListener* _listener);
static ObjectCache* getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener);
static std::unique_ptr<llvm::Module> getObject(std::string const& id);
/// Clears cache storage
static void clear();
/// Loads all available cached objects to ExecutionEngine
static void preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache);
};
}

10
evmjit/libevmjit/Common.h

@ -1,11 +1,12 @@
#pragma once
#include <vector>
#include <tuple>
#include <cstdint>
#ifdef _MSC_VER
#define EXPORT __declspec(dllexport)
#define EXPORT __declspec(dllexport)
#define _ALLOW_KEYWORD_MACROS
#define noexcept throw()
#else
#define EXPORT
#endif
@ -18,12 +19,9 @@ namespace jit
{
using byte = uint8_t;
using bytes = std::vector<byte>;
using bytes_ref = std::tuple<byte const*, size_t>;
using code_iterator = byte const*;
struct NoteChannel {}; // FIXME: Use some log library?
enum class ReturnCode
{
// Success codes
@ -33,7 +31,7 @@ enum class ReturnCode
// Standard error codes
OutOfGas = -1,
StackTooSmall = -2,
StackUnderflow = -2,
BadJumpDestination = -3,
BadInstruction = -4,
Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected

78
evmjit/libevmjit/Compiler.cpp

@ -6,13 +6,9 @@
#include <sstream>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/ADT/PostOrderIterator.h>
#include <llvm/IR/CFG.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/MDBuilder.h>
#include <llvm/PassManager.h>
#include <llvm/Transforms/Scalar.h>
#include "preprocessor/llvm_includes_end.h"
#include "Instruction.h"
@ -93,7 +89,7 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn
}
}
llvm::BasicBlock* Compiler::getJumpTableBlock()
llvm::BasicBlock* Compiler::getJumpTableBlock(RuntimeManager& _runtimeManager)
{
if (!m_jumpTableBlock)
{
@ -101,7 +97,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock()
InsertPointGuard g{m_builder};
m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
auto dest = m_builder.CreatePHI(Type::Word, 8, "target");
auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock());
auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock(_runtimeManager));
for (auto&& p : m_basicBlocks)
{
if (p.second.isJumpDest())
@ -111,21 +107,20 @@ llvm::BasicBlock* Compiler::getJumpTableBlock()
return m_jumpTableBlock->llvm();
}
llvm::BasicBlock* Compiler::getBadJumpBlock()
llvm::BasicBlock* Compiler::getBadJumpBlock(RuntimeManager& _runtimeManager)
{
if (!m_badJumpBlock)
{
m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true));
InsertPointGuard g{m_builder};
m_builder.SetInsertPoint(m_badJumpBlock->llvm());
m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination));
_runtimeManager.exit(ReturnCode::BadJumpDestination);
}
return m_badJumpBlock->llvm();
}
std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id)
{
auto compilationStartTime = std::chrono::high_resolution_clock::now();
auto module = std::unique_ptr<llvm::Module>(new llvm::Module(_id, m_builder.getContext()));
// Create main function
@ -137,6 +132,17 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc);
m_builder.SetInsertPoint(entryBlock);
createBasicBlocks(_begin, _end);
// Init runtime structures.
RuntimeManager runtimeManager(m_builder, _begin, _end);
GasMeter gasMeter(m_builder, runtimeManager);
Memory memory(runtimeManager, gasMeter);
Ext ext(runtimeManager, memory);
Stack stack(m_builder, runtimeManager);
runtimeManager.setStack(stack); // Runtime Manager will free stack memory
Arith256 arith(m_builder);
auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words");
auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress);
auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp");
@ -149,24 +155,14 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf");
auto r = m_builder.CreateCall(setjmp, jmpBuf);
auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0));
createBasicBlocks(_begin, _end);
// Init runtime structures.
RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end);
GasMeter gasMeter(m_builder, runtimeManager);
Memory memory(runtimeManager, gasMeter);
Ext ext(runtimeManager, memory);
Stack stack(m_builder, runtimeManager);
Arith256 arith(m_builder);
runtimeManager.setJmpBuf(jmpBuf);
// TODO: Create Stop basic block on demand
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc);
auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm();
auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0);
m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue);
m_builder.CreateCondBr(normalFlow, firstBB, abortBB, Type::expectTrue);
for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt)
{
@ -180,10 +176,10 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
// Code for special blocks:
// TODO: move to separate function.
m_builder.SetInsertPoint(m_stopBB);
m_builder.CreateRet(Constant::get(ReturnCode::Stop));
runtimeManager.exit(ReturnCode::Stop);
m_builder.SetInsertPoint(abortBB);
m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas));
runtimeManager.exit(ReturnCode::OutOfGas);
removeDeadBlocks();
@ -230,16 +226,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
dumpCFGifRequired("blocks-sync.dot");
if (m_jumpTableBlock && m_options.rewriteSwitchToBranches)
{
llvm::FunctionPassManager fpManager(module.get());
fpManager.add(llvm::createLowerSwitchPass());
fpManager.doInitialization();
fpManager.run(*m_mainFunc);
}
auto compilationEndTime = std::chrono::high_resolution_clock::now();
clog(JIT) << "JIT: " << std::chrono::duration_cast<std::chrono::milliseconds>(compilationEndTime - compilationStartTime).count();
return module;
}
@ -516,7 +502,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
auto val = stack.pop();
static_cast<void>(val);
// Generate a dummy use of val to make sure that a get(0) will be emitted at this point,
// so that StackTooSmall will be thrown
// so that StackUnderflow will be thrown
// m_builder.CreateICmpEQ(val, val, "dummy");
break;
}
@ -600,7 +586,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
auto&& c = constant->getValue();
auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1;
auto it = m_basicBlocks.find(targetIdx);
targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock();
targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(_runtimeManager);
}
// TODO: Improve; check for constants
@ -613,7 +599,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
else
{
_basicBlock.setJumpTarget(target);
m_builder.CreateBr(getJumpTableBlock());
m_builder.CreateBr(getJumpTableBlock(_runtimeManager));
}
}
else // JUMPI
@ -629,7 +615,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
else
{
_basicBlock.setJumpTarget(target);
m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock);
m_builder.CreateCondBr(cond, getJumpTableBlock(_runtimeManager), _nextBasicBlock);
}
}
break;
@ -769,7 +755,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
case Instruction::CALL:
case Instruction::CALLCODE:
{
auto callGas256 = stack.pop();
auto callGas = stack.pop();
auto codeAddress = stack.pop();
auto value = stack.pop();
auto inOff = stack.pop();
@ -787,13 +773,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
if (inst == Instruction::CALLCODE)
receiveAddress = _runtimeManager.get(RuntimeData::Address);
auto gas = _runtimeManager.getGas();
_gasMeter.count(callGas256);
auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas);
auto gasLeft = m_builder.CreateNSWSub(gas, callGas);
_runtimeManager.setGas(callGas);
auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress);
_gasMeter.giveBack(gasLeft);
auto ret = _ext.call(callGas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress);
_gasMeter.count(m_builder.getInt64(0), _runtimeManager.getJmpBuf(), _runtimeManager.getGasPtr());
stack.push(ret);
break;
}
@ -806,14 +787,14 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
_memory.require(index, size);
_runtimeManager.registerReturnData(index, size);
m_builder.CreateRet(Constant::get(ReturnCode::Return));
_runtimeManager.exit(ReturnCode::Return);
break;
}
case Instruction::SUICIDE:
{
_runtimeManager.registerSuicide(stack.pop());
m_builder.CreateRet(Constant::get(ReturnCode::Suicide));
_runtimeManager.exit(ReturnCode::Suicide);
break;
}
@ -857,6 +838,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
// Block may have no terminator if the next instruction is a jump destination.
if (!_basicBlock.llvm()->getTerminator())
m_builder.CreateBr(_nextBasicBlock);
m_builder.SetInsertPoint(_basicBlock.llvm()->getFirstNonPHI());
_runtimeManager.checkStackLimit(_basicBlock.localStack().getMaxSize(), _basicBlock.localStack().getDiff());
}

4
evmjit/libevmjit/Compiler.h

@ -38,9 +38,9 @@ private:
void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock);
llvm::BasicBlock* getJumpTableBlock();
llvm::BasicBlock* getJumpTableBlock(RuntimeManager& _runtimeManager);
llvm::BasicBlock* getBadJumpBlock();
llvm::BasicBlock* getBadJumpBlock(RuntimeManager& _runtimeManager);
void removeDeadBlocks();

9
evmjit/libevmjit/Endianness.cpp

@ -2,6 +2,7 @@
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/Support/Host.h>
#include "preprocessor/llvm_includes_end.h"
#include "Type.h"
@ -15,13 +16,7 @@ namespace jit
llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word)
{
union tester
{
unsigned int x;
unsigned char isLE;
};
if (tester{1}.isLE)
if (llvm::sys::IsLittleEndianHost)
{
// FIXME: Disabled because of problems with BYTE
//if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(_word))

1
evmjit/libevmjit/ExecStats.cpp

@ -67,6 +67,7 @@ char const* getExecStateName(ExecState _state)
case ExecState::CacheLoad: return "CacheLoad";
case ExecState::CacheWrite: return "CacheWrite";
case ExecState::Compilation: return "Compilation";
case ExecState::Optimization: return "Optimization";
case ExecState::CodeGen: return "CodeGen";
case ExecState::Execution: return "Execution";
case ExecState::Return: return "Return";

1
evmjit/libevmjit/ExecStats.h

@ -1,5 +1,6 @@
#pragma once
#include <vector>
#include <string>
#include <chrono>

117
evmjit/libevmjit/ExecutionEngine.cpp

@ -1,8 +1,11 @@
#include "ExecutionEngine.h"
#include <array>
#include <cstdlib> // env options
#include <mutex>
#include <iostream>
#include <unordered_map>
#include <cstdlib>
#include <cstring>
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
@ -12,10 +15,13 @@
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h"
#include "Runtime.h"
#include "Compiler.h"
#include "Optimizer.h"
#include "Cache.h"
#include "ExecStats.h"
#include "Utils.h"
@ -48,42 +54,79 @@ std::string codeHash(i256 const& _hash)
return str;
}
bool getEnvOption(char const* _name, bool _default)
void printVersion()
{
auto var = std::getenv(_name);
if (!var)
return _default;
return std::strtol(var, nullptr, 10) != 0;
std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n"
<< " EVMJIT version " << EVMJIT_VERSION << "\n"
#ifdef NDEBUG
<< " Optimized build, " EVMJIT_VERSION_FULL "\n"
#else
<< " DEBUG build, " EVMJIT_VERSION_FULL "\n"
#endif
<< " Built " << __DATE__ << " (" << __TIME__ << ")\n"
<< std::endl;
}
bool showInfo()
namespace cl = llvm::cl;
cl::opt<bool> g_optimize{"O", cl::desc{"Optimize"}};
cl::opt<CacheMode> g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"},
cl::values(
clEnumValN(CacheMode::on, "1", "Enabled"),
clEnumValN(CacheMode::off, "0", "Disabled"),
clEnumValN(CacheMode::read, "r", "Read only. No new objects are added to cache."),
clEnumValN(CacheMode::write, "w", "Write only. No objects are loaded from cache."),
clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."),
clEnumValN(CacheMode::preload, "p", "Preload all cached objects."),
clEnumValEnd)};
cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}};
cl::opt<bool> g_dump{"dump", cl::desc{"Dump LLVM IR module"}};
void parseOptions()
{
auto show = getEnvOption("EVMJIT_INFO", false);
if (show)
{
std::cout << "The Ethereum EVM JIT " EVMJIT_VERSION_FULL " LLVM " LLVM_VERSION << std::endl;
}
return show;
static llvm::llvm_shutdown_obj shutdownObj{};
cl::AddExtraVersionPrinter(printVersion);
//cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler");
// FIXME: LLVM workaround:
// Manually select instruction scheduler other than "source".
// "source" scheduler has a bug: http://llvm.org/bugs/show_bug.cgi?id=22304
auto envLine = std::getenv("EVMJIT");
auto commandLine = std::string{"evmjit "} + (envLine ? envLine : "") + " -pre-RA-sched=list-burr\0";
static const auto c_maxArgs = 20;
char const* argv[c_maxArgs] = {nullptr, };
auto arg = std::strtok(&*commandLine.begin(), " ");
auto i = 0;
for (; i < c_maxArgs && arg; ++i, arg = std::strtok(nullptr, " "))
argv[i] = arg;
cl::ParseCommandLineOptions(i, argv, "Ethereum EVM JIT Compiler");
}
}
ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
{
static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false);
static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true);
static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false);
static auto infoShown = showInfo();
(void) infoShown;
static std::once_flag flag;
std::call_once(flag, parseOptions);
std::unique_ptr<ExecStats> listener{new ExecStats};
listener->stateChanged(ExecState::Started);
auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr;
bool preloadCache = g_cache == CacheMode::preload;
if (preloadCache)
g_cache = CacheMode::on;
// TODO: Do not pseudo-init the cache every time
auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr;
static std::unordered_map<std::string, uint64_t> funcCache;
static std::unique_ptr<llvm::ExecutionEngine> ee;
if (!ee)
{
if (g_cache == CacheMode::clear)
Cache::clear();
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
@ -91,7 +134,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
llvm::EngineBuilder builder(module.get());
builder.setEngineKind(llvm::EngineKind::JIT);
builder.setUseMCJIT(true);
builder.setOptLevel(llvm::CodeGenOpt::None);
builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);
auto triple = llvm::Triple(llvm::sys::getProcessTriple());
if (triple.getOS() == llvm::Triple::OSType::Win32)
@ -103,14 +146,21 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
return ReturnCode::LLVMConfigError;
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
ee->setObjectCache(objectCache);
if (preloadCache)
Cache::preload(*ee, funcCache);
}
static StatsCollector statsCollector;
auto mainFuncName = codeHash(_data->codeHash);
Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls
m_runtime.init(_data, _env);
EntryFuncPtr entryFuncPtr = nullptr;
auto it = funcCache.find(mainFuncName);
if (it != funcCache.end())
entryFuncPtr = (EntryFuncPtr) it->second;
auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
if (!entryFuncPtr)
{
auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
@ -118,9 +168,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
{
listener->stateChanged(ExecState::Compilation);
assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code?
module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, mainFuncName);
module = Compiler{{}}.compile(_data->code, _data->code + _data->codeSize, mainFuncName);
if (g_optimize)
{
listener->stateChanged(ExecState::Optimization);
optimize(*module);
}
}
if (debugDumpModule)
if (g_dump)
module->dump();
ee->addModule(module.get());
@ -131,18 +187,19 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
if (!CHECK(entryFuncPtr))
return ReturnCode::LLVMLinkError;
if (it == funcCache.end())
funcCache[mainFuncName] = (uint64_t) entryFuncPtr;
listener->stateChanged(ExecState::Execution);
auto returnCode = entryFuncPtr(&runtime);
auto returnCode = entryFuncPtr(&m_runtime);
listener->stateChanged(ExecState::Return);
if (returnCode == ReturnCode::Return)
{
returnData = runtime.getReturnData(); // Save reference to return data
std::swap(m_memory, runtime.getMemory()); // Take ownership of memory
}
returnData = m_runtime.getReturnData(); // Save reference to return data
listener->stateChanged(ExecState::Finished);
if (statsCollectingEnabled)
if (g_stats)
statsCollector.stats.push_back(std::move(listener));
return returnCode;

7
evmjit/libevmjit/ExecutionEngine.h

@ -2,7 +2,7 @@
#include <memory>
#include "RuntimeData.h"
#include "Runtime.h"
namespace dev
{
@ -17,6 +17,7 @@ enum class ExecState
CacheLoad,
CacheWrite,
Compilation,
Optimization,
CodeGen,
Execution,
Return,
@ -50,9 +51,7 @@ public:
bytes_ref returnData;
private:
/// After execution, if RETURN used, memory is moved there
/// to allow client copy the returned data
bytes m_memory;
Runtime m_runtime;
};
}

10
evmjit/libevmjit/Ext.cpp

@ -41,7 +41,7 @@ std::array<FuncDesc, sizeOf<EnvFunc>::value> const& getEnvFuncDescs()
FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})},
FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})},
FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})},
FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::Gas, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})},
FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})},
@ -136,7 +136,7 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V
return address;
}
llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress)
llvm::Value* Ext::call(llvm::Value* _callGas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress)
{
auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress);
auto inBeg = m_memoryMan.getBytePtr(_inOff);
@ -144,7 +144,11 @@ llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::
auto outBeg = m_memoryMan.getBytePtr(_outOff);
auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size");
auto codeAddress = Endianness::toBE(m_builder, _codeAddress);
auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)});
auto callGas = m_builder.CreateSelect(
m_builder.CreateICmpULE(_callGas, m_builder.CreateZExt(Constant::gasMax, Type::Word)),
m_builder.CreateTrunc(_callGas, Type::Gas),
Constant::gasMax);
auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), callGas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)});
return m_builder.CreateZExt(ret, Type::Word, "ret");
}

2
evmjit/libevmjit/Ext.h

@ -51,7 +51,7 @@ public:
llvm::Value* balance(llvm::Value* _address);
llvm::Value* calldataload(llvm::Value* _index);
llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize);
llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress);
llvm::Value* call(llvm::Value* _callGas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress);
llvm::Value* blockhash(llvm::Value* _number);
llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize);

230
evmjit/libevmjit/GasMeter.cpp

@ -17,52 +17,113 @@ namespace jit
namespace // Helper functions
{
int64_t const c_stepGas = 1;
int64_t const c_balanceGas = 20;
int64_t const c_sha3Gas = 10;
int64_t const c_sha3WordGas = 10;
int64_t const c_sloadGas = 20;
int64_t const c_sstoreSetGas = 300;
int64_t const c_sstoreResetGas = 100;
int64_t const c_sstoreRefundGas = 100;
int64_t const c_createGas = 100;
int64_t const c_createDataGas = 5;
int64_t const c_callGas = 20;
int64_t const c_expGas = 1;
int64_t const c_expByteGas = 1;
int64_t const c_memoryGas = 1;
int64_t const c_txDataZeroGas = 1;
int64_t const c_txDataNonZeroGas = 5;
int64_t const c_txGas = 500;
int64_t const c_logGas = 32;
int64_t const c_logDataGas = 1;
int64_t const c_logTopicGas = 32;
int64_t const c_copyGas = 1;
int64_t const c_stepGas[] = {0, 2, 3, 5, 8, 10, 20};
int64_t const c_expByteGas = 10;
int64_t const c_sha3Gas = 30;
int64_t const c_sha3WordGas = 6;
int64_t const c_sloadGas = 50;
int64_t const c_sstoreSetGas = 20000;
int64_t const c_sstoreResetGas = 5000;
int64_t const c_sstoreClearGas = 5000;
int64_t const c_jumpdestGas = 1;
int64_t const c_logGas = 375;
int64_t const c_logTopicGas = 375;
int64_t const c_logDataGas = 8;
int64_t const c_callGas = 40;
int64_t const c_createGas = 32000;
int64_t const c_memoryGas = 3;
int64_t const c_copyGas = 3;
int64_t getStepCost(Instruction inst)
{
switch (inst)
{
default: // Assumes instruction code is valid
return c_stepGas;
// Tier 0
case Instruction::STOP:
case Instruction::RETURN:
case Instruction::SUICIDE:
case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore()
return 0;
case Instruction::EXP: return c_expGas;
case Instruction::SLOAD: return c_sloadGas;
case Instruction::SHA3: return c_sha3Gas;
case Instruction::BALANCE: return c_balanceGas;
case Instruction::CALL:
case Instruction::CALLCODE: return c_callGas;
case Instruction::CREATE: return c_createGas;
return c_stepGas[0];
// Tier 1
case Instruction::ADDRESS:
case Instruction::ORIGIN:
case Instruction::CALLER:
case Instruction::CALLVALUE:
case Instruction::CALLDATASIZE:
case Instruction::CODESIZE:
case Instruction::GASPRICE:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
case Instruction::NUMBER:
case Instruction::DIFFICULTY:
case Instruction::GASLIMIT:
case Instruction::POP:
case Instruction::PC:
case Instruction::MSIZE:
case Instruction::GAS:
return c_stepGas[1];
// Tier 2
case Instruction::ADD:
case Instruction::SUB:
case Instruction::LT:
case Instruction::GT:
case Instruction::SLT:
case Instruction::SGT:
case Instruction::EQ:
case Instruction::ISZERO:
case Instruction::AND:
case Instruction::OR:
case Instruction::XOR:
case Instruction::NOT:
case Instruction::BYTE:
case Instruction::CALLDATALOAD:
case Instruction::CALLDATACOPY:
case Instruction::CODECOPY:
case Instruction::MLOAD:
case Instruction::MSTORE:
case Instruction::MSTORE8:
case Instruction::ANY_PUSH:
case Instruction::ANY_DUP:
case Instruction::ANY_SWAP:
return c_stepGas[2];
// Tier 3
case Instruction::MUL:
case Instruction::DIV:
case Instruction::SDIV:
case Instruction::MOD:
case Instruction::SMOD:
case Instruction::SIGNEXTEND:
return c_stepGas[3];
// Tier 4
case Instruction::ADDMOD:
case Instruction::MULMOD:
case Instruction::JUMP:
return c_stepGas[4];
// Tier 5
case Instruction::EXP:
case Instruction::JUMPI:
return c_stepGas[5];
// Tier 6
case Instruction::BALANCE:
case Instruction::EXTCODESIZE:
case Instruction::EXTCODECOPY:
case Instruction::BLOCKHASH:
return c_stepGas[6];
case Instruction::SHA3:
return c_sha3Gas;
case Instruction::SLOAD:
return c_sloadGas;
case Instruction::JUMPDEST:
return c_jumpdestGas;
case Instruction::LOG0:
case Instruction::LOG1:
@ -73,7 +134,16 @@ int64_t getStepCost(Instruction inst)
auto numTopics = static_cast<int64_t>(inst) - static_cast<int64_t>(Instruction::LOG0);
return c_logGas + numTopics * c_logTopicGas;
}
case Instruction::CALL:
case Instruction::CALLCODE:
return c_callGas;
case Instruction::CREATE:
return c_createGas;
}
return 0; // TODO: Add UNREACHABLE macro
}
}
@ -82,34 +152,36 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
CompilerHelper(_builder),
m_runtimeManager(_runtimeManager)
{
auto module = getModule();
llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas};
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module);
InsertPointGuard guard(m_builder);
llvm::Type* gasCheckArgs[] = {Type::Gas->getPointerTo(), Type::Gas, Type::BytePtr};
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", getModule());
m_gasCheckFunc->setDoesNotThrow();
m_gasCheckFunc->setDoesNotCapture(1);
auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc);
auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);
auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc);
auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);
auto rt = &m_gasCheckFunc->getArgumentList().front();
rt->setName("rt");
auto cost = rt->getNextNode();
auto gasPtr = &m_gasCheckFunc->getArgumentList().front();
gasPtr->setName("gasPtr");
auto cost = gasPtr->getNextNode();
cost->setName("cost");
auto jmpBuf = cost->getNextNode();
jmpBuf->setName("jmpBuf");
InsertPointGuard guard(m_builder);
m_builder.SetInsertPoint(checkBB);
auto gas = m_runtimeManager.getGas();
gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated");
auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions
m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);
m_builder.SetInsertPoint(outOfGasBB);
m_runtimeManager.abort();
m_builder.CreateUnreachable();
auto gas = m_builder.CreateLoad(gasPtr, "gas");
auto gasUpdated = m_builder.CreateNSWSub(gas, cost, "gasUpdated");
auto gasOk = m_builder.CreateICmpSGE(gasUpdated, m_builder.getInt64(0), "gasOk"); // gas >= 0, with gas == 0 we can still do 0 cost instructions
m_builder.CreateCondBr(gasOk, updateBB, outOfGasBB, Type::expectTrue);
m_builder.SetInsertPoint(updateBB);
m_runtimeManager.setGas(gas);
m_builder.CreateStore(gasUpdated, gasPtr);
m_builder.CreateRetVoid();
m_builder.SetInsertPoint(outOfGasBB);
m_runtimeManager.abort(jmpBuf);
m_builder.CreateUnreachable();
}
void GasMeter::count(Instruction _inst)
@ -117,13 +189,13 @@ void GasMeter::count(Instruction _inst)
if (!m_checkCall)
{
// Create gas check call with mocked block cost at begining of current cost-block
m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)});
m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getGasPtr(), llvm::UndefValue::get(Type::Gas), m_runtimeManager.getJmpBuf()});
}
m_blockCost += getStepCost(_inst);
}
void GasMeter::count(llvm::Value* _cost)
void GasMeter::count(llvm::Value* _cost, llvm::Value* _jmpBuf, llvm::Value* _gasPtr)
{
if (_cost->getType() == Type::Word)
{
@ -134,7 +206,7 @@ void GasMeter::count(llvm::Value* _cost)
}
assert(_cost->getType() == Type::Gas);
createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost});
createCall(m_gasCheckFunc, {_gasPtr ? _gasPtr : m_runtimeManager.getGasPtr(), _cost, _jmpBuf ? _jmpBuf : m_runtimeManager.getJmpBuf()});
}
void GasMeter::countExp(llvm::Value* _exponent)
@ -145,25 +217,31 @@ void GasMeter::countExp(llvm::Value* _exponent)
// OPT: Can gas update be done in exp algorithm?
auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word);
auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits");
auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8));
count(sigBytes);
auto t = llvm::APInt{256, 1};
auto c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(1), m_builder.getInt64(0));
for (auto i = 2; i <= 32; ++i)
{
t <<= 8;
c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(i), c);
}
// FIXME: Does not work because of LLVM bug: https://llvm.org/bugs/show_bug.cgi?id=22304
// auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word);
// auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
// auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
// auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits");
// auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8));
count(m_builder.CreateNUWMul(c, m_builder.getInt64(c_expByteGas)));
}
void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue)
{
auto oldValue = _ext.sload(_index);
auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero");
auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero");
auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete");
static_assert(c_sstoreResetGas == c_sstoreClearGas, "Update SSTORE gas cost");
auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost");
cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost");
count(cost);
}
@ -171,8 +249,8 @@ void GasMeter::countLogData(llvm::Value* _dataLength)
{
assert(m_checkCall);
assert(m_blockCost > 0); // LOGn instruction is already counted
static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter.");
count(_dataLength);
static_assert(c_logDataGas != 1, "Log data gas cost has changed. Update GasMeter.");
count(m_builder.CreateNUWMul(_dataLength, Constant::get(c_logDataGas))); // TODO: Use i64
}
void GasMeter::countSha3Data(llvm::Value* _dataLength)
@ -213,16 +291,16 @@ void GasMeter::commitCostBlock()
assert(m_blockCost == 0);
}
void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords)
void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords, llvm::Value* _jmpBuf, llvm::Value* _gasPtr)
{
static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter.");
count(_additionalMemoryInWords);
static_assert(c_memoryGas != 1, "Memory gas cost has changed. Update GasMeter.");
count(_additionalMemoryInWords, _jmpBuf, _gasPtr);
}
void GasMeter::countCopy(llvm::Value* _copyWords)
{
static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter.");
count(_copyWords);
static_assert(c_copyGas != 1, "Copy gas cost has changed. Update GasMeter.");
count(m_builder.CreateNUWMul(_copyWords, m_builder.getInt64(c_copyGas)));
}
}

4
evmjit/libevmjit/GasMeter.h

@ -20,7 +20,7 @@ public:
void count(Instruction _inst);
/// Count additional cost
void count(llvm::Value* _cost);
void count(llvm::Value* _cost, llvm::Value* _jmpBuf = nullptr, llvm::Value* _gasPtr = nullptr);
/// Calculate & count gas cost for SSTORE instruction
void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue);
@ -41,7 +41,7 @@ public:
void giveBack(llvm::Value* _gas);
/// Generate code that checks the cost of additional memory used by program
void countMemory(llvm::Value* _additionalMemoryInWords);
void countMemory(llvm::Value* _additionalMemoryInWords, llvm::Value* _jmpBuf, llvm::Value* _gasPtr);
/// Count addional gas cost for memory copy
void countCopy(llvm::Value* _copyWords);

158
evmjit/libevmjit/Memory.cpp

@ -19,6 +19,7 @@ namespace jit
Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed
m_memory{getBuilder(), _runtimeManager.getMem()},
m_gasMeter(_gasMeter)
{}
@ -27,20 +28,20 @@ llvm::Function* Memory::getRequireFunc()
auto& func = m_require;
if (!func)
{
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word};
llvm::Type* argTypes[] = {Array::getType()->getPointerTo(), Type::Word, Type::Word, Type::BytePtr, Type::GasPtr};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
auto rt = func->arg_begin();
rt->setName("rt");
auto offset = rt->getNextNode();
offset->setName("offset");
auto size = offset->getNextNode();
size->setName("size");
llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule());
llvm::AttrBuilder attrBuilder;
attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder));
func->setDoesNotThrow();
auto mem = &func->getArgumentList().front();
mem->setName("mem");
auto blkOffset = mem->getNextNode();
blkOffset->setName("blkOffset");
auto blkSize = blkOffset->getNextNode();
blkSize->setName("blkSize");
auto jmpBuf = blkSize->getNextNode();
jmpBuf->setName("jmpBuf");
auto gas = jmpBuf->getNextNode();
gas->setName("gas");
auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func);
auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
@ -51,40 +52,38 @@ llvm::Function* Memory::getRequireFunc()
// BB "Pre": Ignore checks with size 0
m_builder.SetInsertPoint(preBB);
auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0));
m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB);
m_builder.CreateCondBr(m_builder.CreateICmpNE(blkSize, Constant::get(0)), checkBB, returnBB, Type::expectTrue);
// BB "Check"
m_builder.SetInsertPoint(checkBB);
auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word);
auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res");
auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1");
auto rtPtr = getRuntimeManager().getRuntimePtr();
auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
auto currSize = m_builder.CreateLoad(sizePtr, "currSize");
auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall");
auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded");
m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?
static const auto c_inputMax = uint64_t(1) << 33; // max value of blkSize and blkOffset that will not result in integer overflow in calculations below
auto blkOffsetOk = m_builder.CreateICmpULE(blkOffset, Constant::get(c_inputMax), "blkOffsetOk");
auto blkO = m_builder.CreateSelect(blkOffsetOk, m_builder.CreateTrunc(blkOffset, Type::Size), m_builder.getInt64(c_inputMax), "bklO");
auto blkSizeOk = m_builder.CreateICmpULE(blkSize, Constant::get(c_inputMax), "blkSizeOk");
auto blkS = m_builder.CreateSelect(blkSizeOk, m_builder.CreateTrunc(blkSize, Type::Size), m_builder.getInt64(c_inputMax), "bklS");
auto sizeReq0 = m_builder.CreateNUWAdd(blkO, blkS, "sizeReq0");
auto sizeReq = m_builder.CreateAnd(m_builder.CreateNUWAdd(sizeReq0, m_builder.getInt64(31)), uint64_t(-1) << 5, "sizeReq"); // s' = ((s0 + 31) / 32) * 32
auto sizeCur = m_memory.size(mem);
auto sizeOk = m_builder.CreateICmpULE(sizeReq, sizeCur, "sizeOk");
m_builder.CreateCondBr(sizeOk, returnBB, resizeBB, Type::expectTrue);
// BB "Resize"
m_builder.SetInsertPoint(resizeBB);
// Check gas first
uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res");
auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0);
auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2");
auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow");
wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired);
wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq");
sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k
auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
m_gasMeter.countMemory(newWords);
auto w1 = m_builder.CreateLShr(sizeReq, 5);
auto w1s = m_builder.CreateNUWMul(w1, w1);
auto c1 = m_builder.CreateAdd(m_builder.CreateNUWMul(w1, m_builder.getInt64(3)), m_builder.CreateLShr(w1s, 9));
auto w0 = m_builder.CreateLShr(sizeCur, 5);
auto w0s = m_builder.CreateNUWMul(w0, w0);
auto c0 = m_builder.CreateAdd(m_builder.CreateNUWMul(w0, m_builder.getInt64(3)), m_builder.CreateLShr(w0s, 9));
auto cc = m_builder.CreateNUWSub(c1, c0);
auto costOk = m_builder.CreateAnd(blkOffsetOk, blkSizeOk, "costOk");
auto c = m_builder.CreateSelect(costOk, cc, m_builder.getInt64(std::numeric_limits<int64_t>::max()), "c");
m_gasMeter.count(c, jmpBuf, gas);
// Resize
m_builder.CreateStore(sizeRequired, sizePtr);
auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData");
auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3);
m_builder.CreateStore(newData, dataPtr);
m_memory.extend(mem, sizeReq);
m_builder.CreateBr(returnBB);
// BB "Return"
@ -94,12 +93,12 @@ llvm::Function* Memory::getRequireFunc()
return func;
}
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType)
{
auto isWord = _valueType == Type::Word;
llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType};
llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word};
llvm::Type* storeArgs[] = {Array::getType()->getPointerTo(), Type::Word, _valueType};
llvm::Type* loadArgs[] = {Array::getType()->getPointerTo(), Type::Word};
auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false);
auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());
@ -107,28 +106,25 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet
InsertPointGuard guard(m_builder); // Restores insert point at function exit
m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
auto rt = func->arg_begin();
rt->setName("rt");
auto index = rt->getNextNode();
auto mem = &func->getArgumentList().front();
mem->setName("mem");
auto index = mem->getNextNode();
index->setName("index");
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
this->require(index, Constant::get(valueSize));
auto ptr = getBytePtr(index);
if (isWord)
ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
if (_isStore)
{
llvm::Value* value = index->getNextNode();
value->setName("value");
if (isWord)
value = Endianness::toBE(m_builder, value);
m_builder.CreateStore(value, ptr);
auto valueArg = index->getNextNode();
valueArg->setName("value");
auto value = isWord ? Endianness::toBE(m_builder, valueArg) : valueArg;
auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size));
auto valuePtr = m_builder.CreateBitCast(memPtr, _valueType->getPointerTo(), "valuePtr");
m_builder.CreateStore(value, valuePtr);
m_builder.CreateRetVoid();
}
else
{
llvm::Value* ret = m_builder.CreateLoad(ptr);
auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size));
llvm::Value* ret = m_builder.CreateLoad(memPtr);
ret = Endianness::toNative(m_builder, ret);
m_builder.CreateRet(ret);
}
@ -140,7 +136,7 @@ llvm::Function* Memory::getLoadWordFunc()
{
auto& func = m_loadWord;
if (!func)
func = createFunc(false, Type::Word, m_gasMeter);
func = createFunc(false, Type::Word);
return func;
}
@ -148,7 +144,7 @@ llvm::Function* Memory::getStoreWordFunc()
{
auto& func = m_storeWord;
if (!func)
func = createFunc(true, Type::Word, m_gasMeter);
func = createFunc(true, Type::Word);
return func;
}
@ -156,39 +152,41 @@ llvm::Function* Memory::getStoreByteFunc()
{
auto& func = m_storeByte;
if (!func)
func = createFunc(true, Type::Byte, m_gasMeter);
func = createFunc(true, Type::Byte);
return func;
}
llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr});
require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8));
return createCall(getLoadWordFunc(), {getRuntimeManager().getMem(), _addr});
}
void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word});
require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8));
createCall(getStoreWordFunc(), {getRuntimeManager().getMem(), _addr, _word});
}
void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
require(_addr, Constant::get(Type::Byte->getPrimitiveSizeInBits() / 8));
auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte});
createCall(getStoreByteFunc(), {getRuntimeManager().getMem(), _addr, byte});
}
llvm::Value* Memory::getData()
{
auto rtPtr = getRuntimeManager().getRuntimePtr();
auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3);
return m_builder.CreateLoad(dataPtr, "data");
auto memPtr = m_builder.CreateBitCast(getRuntimeManager().getMem(), Type::BytePtr->getPointerTo());
auto data = m_builder.CreateLoad(memPtr, "data");
assert(data->getType() == Type::BytePtr);
return data;
}
llvm::Value* Memory::getSize()
{
auto rtPtr = getRuntimeManager().getRuntimePtr();
auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
return m_builder.CreateLoad(sizePtr, "size");
return m_builder.CreateZExt(m_memory.size(), Type::Word, "msize"); // TODO: Allow placing i64 on stack
}
llvm::Value* Memory::getBytePtr(llvm::Value* _index)
@ -204,7 +202,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size)
if (!constant->getValue())
return;
}
createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size});
createCall(getRequireFunc(), {getRuntimeManager().getMem(), _offset, _size, getRuntimeManager().getJmpBuf(), getRuntimeManager().getGasPtr()});
}
void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
@ -233,28 +231,18 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value*
auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64);
auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize);
auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes);
auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner);
auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner, "bytesToCopy");
auto bytesToZero = m_builder.CreateNUWSub(reqBytes, bytesToCopy, "bytesToZero");
auto src = m_builder.CreateGEP(_srcPtr, idx64, "src");
auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64
auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst");
auto padIdx = m_builder.CreateNUWAdd(dstIdx, bytesToCopy, "padIdx");
auto dst = m_memory.getPtr(getRuntimeManager().getMem(), dstIdx);
auto pad = m_memory.getPtr(getRuntimeManager().getMem(), padIdx);
m_builder.CreateMemCpy(dst, src, bytesToCopy, 0);
m_builder.CreateMemSet(pad, m_builder.getInt8(0), bytesToZero, 0);
}
}
}
}
extern "C"
{
using namespace dev::eth::jit;
EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR
{
auto size = _size->a; // Trunc to 64-bit
auto& memory = _rt->getMemory();
memory.resize(size);
return memory.data();
}
}

6
evmjit/libevmjit/Memory.h

@ -1,6 +1,6 @@
#pragma once
#include "CompilerHelper.h"
#include "Array.h"
namespace dev
{
@ -28,9 +28,11 @@ public:
void require(llvm::Value* _offset, llvm::Value* _size);
private:
Array m_memory;
GasMeter& m_gasMeter;
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter);
llvm::Function* createFunc(bool _isStore, llvm::Type* _type);
llvm::Function* getRequireFunc();
llvm::Function* getLoadWordFunc();

29
evmjit/libevmjit/Optimizer.cpp

@ -0,0 +1,29 @@
#include "Optimizer.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/PassManager.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h>
#include "preprocessor/llvm_includes_end.h"
namespace dev
{
namespace eth
{
namespace jit
{
bool optimize(llvm::Module& _module)
{
auto pm = llvm::PassManager{};
//pm.add(llvm::createFunctionInliningPass(2, 2)); // Produces invalid IR
pm.add(llvm::createCFGSimplificationPass());
//pm.add(llvm::createInstructionCombiningPass()); // Produces invalid runtime results
pm.add(llvm::createAggressiveDCEPass());
pm.add(llvm::createLowerSwitchPass());
return pm.run(_module);
}
}
}
}

19
evmjit/libevmjit/Optimizer.h

@ -0,0 +1,19 @@
#pragma once
namespace llvm
{
class Module;
}
namespace dev
{
namespace eth
{
namespace jit
{
bool optimize(llvm::Module& _module);
}
}
}

25
evmjit/libevmjit/Runtime.cpp

@ -9,20 +9,29 @@ namespace eth
namespace jit
{
Runtime::Runtime(RuntimeData* _data, Env* _env) :
m_data(*_data),
m_env(*_env)
{}
void Runtime::init(RuntimeData* _data, Env* _env)
{
m_data = _data;
m_env = _env;
}
extern "C" void ext_free(void* _data) noexcept;
Runtime::~Runtime()
{
if (m_memData)
ext_free(m_memData); // Use helper free to check memory leaks
}
bytes_ref Runtime::getReturnData() const
{
auto data = m_data.callData;
auto size = static_cast<size_t>(m_data.callDataSize);
auto data = m_data->callData;
auto size = static_cast<size_t>(m_data->callDataSize);
if (data < m_memory.data() || data >= m_memory.data() + m_memory.size() || size == 0)
if (data < m_memData || data >= m_memData + m_memSize || size == 0)
{
assert(size == 0); // data can be an invalid pointer only if size is 0
m_data.callData = nullptr;
m_data->callData = nullptr;
return {};
}

24
evmjit/libevmjit/Runtime.h

@ -9,30 +9,20 @@ namespace eth
namespace jit
{
using StackImpl = std::vector<i256>;
using MemoryImpl = bytes;
class Runtime
{
public:
Runtime(RuntimeData* _data, Env* _env);
Runtime(const Runtime&) = delete;
Runtime& operator=(const Runtime&) = delete;
StackImpl& getStack() { return m_stack; }
MemoryImpl& getMemory() { return m_memory; }
void init(RuntimeData* _data, Env* _env);
EXPORT ~Runtime();
bytes_ref getReturnData() const;
private:
RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract.
Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract.
void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract.
byte* m_memoryData = nullptr;
i256 m_memorySize;
StackImpl m_stack;
MemoryImpl m_memory;
RuntimeData* m_data = nullptr; ///< Pointer to data. Expected by compiled contract.
Env* m_env = nullptr; ///< Pointer to environment proxy. Expected by compiled contract.
byte* m_memData = nullptr;
uint64_t m_memSize = 0;
uint64_t m_memCap = 0;
};
}

87
evmjit/libevmjit/RuntimeManager.cpp

@ -4,6 +4,9 @@
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"
#include "Stack.h"
#include "Utils.h"
namespace dev
{
namespace eth
@ -48,9 +51,7 @@ llvm::StructType* RuntimeManager::getRuntimeType()
{
Type::RuntimeDataPtr, // data
Type::EnvPtr, // Env*
Type::BytePtr, // jmpbuf
Type::BytePtr, // memory data
Type::Word, // memory size
Array::getType() // memory
};
type = llvm::StructType::create(elems, "Runtime");
}
@ -77,30 +78,71 @@ llvm::Twine getName(RuntimeData::Index _index)
case RuntimeData::CodeSize: return "code";
case RuntimeData::CallDataSize: return "callDataSize";
case RuntimeData::Gas: return "gas";
case RuntimeData::Number: return "number";
case RuntimeData::Number: return "number";
case RuntimeData::Timestamp: return "timestamp";
}
}
}
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd):
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd):
CompilerHelper(_builder),
m_jmpBuf(_jmpBuf),
m_codeBegin(_codeBegin),
m_codeEnd(_codeEnd)
{
m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
// save jmpBuf to be used in helper functions
auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2);
m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt");
// Unpack data
auto rtPtr = getRuntimePtr();
m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data");
assert(m_dataPtr->getType() == Type::RuntimeDataPtr);
m_gasPtr = m_builder.CreateStructGEP(m_dataPtr, 0, "gas");
assert(m_gasPtr->getType() == Type::Gas->getPointerTo());
m_memPtr = m_builder.CreateStructGEP(rtPtr, 2, "mem");
assert(m_memPtr->getType() == Array::getType()->getPointerTo());
m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env");
assert(m_envPtr->getType() == Type::EnvPtr);
m_stackSize = m_builder.CreateAlloca(Type::Size, nullptr, "stackSize");
m_builder.CreateStore(m_builder.getInt64(0), m_stackSize);
llvm::Type* checkStackLimitArgs[] = {Type::Size->getPointerTo(), Type::Size, Type::Size, Type::BytePtr};
m_checkStackLimit = llvm::Function::Create(llvm::FunctionType::get(Type::Void, checkStackLimitArgs, false), llvm::Function::PrivateLinkage, "stack.checkSize", getModule());
m_checkStackLimit->setDoesNotThrow();
m_checkStackLimit->setDoesNotCapture(1);
auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_checkStackLimit);
auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_checkStackLimit);
auto outOfStackBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfStack", m_checkStackLimit);
auto currSizePtr = &m_checkStackLimit->getArgumentList().front();
currSizePtr->setName("currSize");
auto max = currSizePtr->getNextNode();
max->setName("max");
auto diff = max->getNextNode();
diff->setName("diff");
auto jmpBuf = diff->getNextNode();
jmpBuf->setName("jmpBuf");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(checkBB);
auto currSize = m_builder.CreateLoad(currSizePtr, "cur");
auto maxSize = m_builder.CreateNUWAdd(currSize, max, "maxSize");
auto ok = m_builder.CreateICmpULE(maxSize, m_builder.getInt64(1024), "ok");
m_builder.CreateCondBr(ok, updateBB, outOfStackBB, Type::expectTrue);
m_builder.SetInsertPoint(updateBB);
auto newSize = m_builder.CreateNSWAdd(currSize, diff);
m_builder.CreateStore(newSize, currSizePtr);
m_builder.CreateRetVoid();
m_builder.SetInsertPoint(outOfStackBB);
abort(jmpBuf);
m_builder.CreateUnreachable();
}
void RuntimeManager::checkStackLimit(size_t _max, int _diff)
{
createCall(m_checkStackLimit, {m_stackSize, m_builder.getInt64(_max), m_builder.getInt64(_diff), getJmpBuf()});
}
llvm::Value* RuntimeManager::getRuntimePtr()
@ -150,7 +192,7 @@ void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value)
void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size)
{
auto memPtr = getBuilder().CreateStructGEP(getRuntimePtr(), 3);
auto memPtr = m_builder.CreateBitCast(getMem(), Type::BytePtr->getPointerTo());
auto mem = getBuilder().CreateLoad(memPtr, "memory");
auto idx = m_builder.CreateTrunc(_offset, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 // TODO: Report bug & fix to LLVM
auto returnDataPtr = getBuilder().CreateGEP(mem, idx);
@ -165,6 +207,14 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress)
set(RuntimeData::SuicideDestAddress, _balanceAddress);
}
void RuntimeManager::exit(ReturnCode _returnCode)
{
if (m_stack)
m_stack->free();
m_builder.CreateRet(Constant::get(_returnCode));
}
void RuntimeManager::abort(llvm::Value* _jmpBuf)
{
auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
@ -213,12 +263,6 @@ llvm::Value* RuntimeManager::getCallDataSize()
return getBuilder().CreateZExt(value, Type::Word);
}
llvm::Value* RuntimeManager::getJmpBufExt()
{
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2);
return getBuilder().CreateLoad(ptr, "jmpBufExt");
}
llvm::Value* RuntimeManager::getGas()
{
auto gas = get(RuntimeData::Gas);
@ -228,7 +272,14 @@ llvm::Value* RuntimeManager::getGas()
llvm::Value* RuntimeManager::getGasPtr()
{
return getPtr(RuntimeData::Gas);
assert(getMainFunction());
return m_gasPtr;
}
llvm::Value* RuntimeManager::getMem()
{
assert(getMainFunction());
return m_memPtr;
}
void RuntimeManager::setGas(llvm::Value* _gas)

25
evmjit/libevmjit/RuntimeManager.h

@ -11,11 +11,12 @@ namespace eth
{
namespace jit
{
class Stack;
class RuntimeManager: public CompilerHelper
{
public:
RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd);
RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd);
llvm::Value* getRuntimePtr();
llvm::Value* getDataPtr();
@ -32,27 +33,41 @@ public:
llvm::Value* getJmpBuf() { return m_jmpBuf; }
void setGas(llvm::Value* _gas);
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
llvm::Value* getMem();
void registerReturnData(llvm::Value* _index, llvm::Value* _size); // TODO: Move to Memory.
void registerSuicide(llvm::Value* _balanceAddress);
void exit(ReturnCode _returnCode);
void abort(llvm::Value* _jmpBuf);
void abort() { abort(getJmpBufExt()); }
void setStack(Stack& _stack) { m_stack = &_stack; }
void setJmpBuf(llvm::Value* _jmpBuf) { m_jmpBuf = _jmpBuf; }
static llvm::StructType* getRuntimeType();
static llvm::StructType* getRuntimeDataType();
void checkStackLimit(size_t _max, int _diff);
private:
llvm::Value* getPtr(RuntimeData::Index _index);
void set(RuntimeData::Index _index, llvm::Value* _value);
llvm::Value* getJmpBufExt();
llvm::Function* m_longjmp = nullptr;
llvm::Value* const m_jmpBuf;
llvm::Value* m_jmpBuf = nullptr;
llvm::Value* m_dataPtr = nullptr;
llvm::Value* m_gasPtr = nullptr;
llvm::Value* m_memPtr = nullptr;
llvm::Value* m_envPtr = nullptr;
llvm::Value* m_stackSize = nullptr;
llvm::Function* m_checkStackLimit = nullptr;
code_iterator m_codeBegin = {};
code_iterator m_codeEnd = {};
Stack* m_stack = nullptr;
};
}

138
evmjit/libevmjit/Stack.cpp

@ -6,6 +6,9 @@
#include "RuntimeManager.h"
#include "Runtime.h"
#include "Utils.h"
#include <set> // DEBUG only
namespace dev
{
@ -16,20 +19,62 @@ namespace jit
Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager):
CompilerHelper(_builder),
m_runtimeManager(_runtimeManager)
m_runtimeManager(_runtimeManager),
m_stack(_builder, "stack")
{}
llvm::Function* Stack::getPushFunc()
{
m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg");
auto& func = m_push;
if (!func)
{
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.push", getModule());
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::WordPtr};
auto extPushFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_push", getModule());
auto rt = &func->getArgumentList().front();
rt->setName("rt");
auto value = rt->getNextNode();
value->setName("value");
using namespace llvm;
using Linkage = GlobalValue::LinkageTypes;
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func);
m_builder.SetInsertPoint(entryBB);
auto a = m_builder.CreateAlloca(Type::Word);
m_builder.CreateStore(value, a);
createCall(extPushFunc, {rt, a});
m_builder.CreateRetVoid();
}
return func;
}
auto module = getModule();
llvm::Function* Stack::getSetFunc()
{
auto& func = m_set;
if (!func)
{
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::Word};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.set", getModule());
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr};
auto extSetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_set", getModule());
llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr};
m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module);
auto rt = &func->getArgumentList().front();
rt->setName("rt");
auto index = rt->getNextNode();
index->setName("index");
auto value = index->getNextNode();
value->setName("value");
llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr};
m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module);
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func);
m_builder.SetInsertPoint(entryBB);
auto a = m_builder.CreateAlloca(Type::Word);
m_builder.CreateStore(value, a);
createCall(extSetFunc, {rt, index, a});
m_builder.CreateRetVoid();
}
return func;
}
llvm::Function* Stack::getPopFunc()
@ -73,16 +118,14 @@ llvm::Function* Stack::getGetFunc()
auto& func = m_get;
if (!func)
{
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr};
func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule());
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size};
auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule());
llvm::Type* argTypes[] = {Type::Size, Type::Size, Type::BytePtr};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.require", getModule());
auto rt = &func->getArgumentList().front();
rt->setName("rt");
auto index = rt->getNextNode();
auto index = &func->getArgumentList().front();
index->setName("index");
auto jmpBuf = index->getNextNode();
auto size = index->getNextNode();
size->setName("size");
auto jmpBuf = size->getNextNode();
jmpBuf->setName("jmpBuf");
InsertPointGuard guard{m_builder};
@ -91,46 +134,44 @@ llvm::Function* Stack::getGetFunc()
auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func);
m_builder.SetInsertPoint(entryBB);
auto valuePtr = createCall(extGetFunc, {rt, index});
auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr));
m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight
auto underflow = m_builder.CreateICmpUGE(index, size, "underflow");
m_builder.CreateCondBr(underflow, underflowBB, returnBB);
m_builder.SetInsertPoint(underflowBB);
m_runtimeManager.abort(jmpBuf);
m_builder.CreateUnreachable();
m_builder.SetInsertPoint(returnBB);
m_builder.CreateRet(valuePtr);
m_builder.CreateRetVoid();
}
return func;
}
llvm::Value* Stack::get(size_t _index)
{
auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()});
return m_builder.CreateLoad(valuePtr);
createCall(getGetFunc(), {m_builder.getInt64(_index), m_stack.size(), m_runtimeManager.getJmpBuf()});
auto value = m_stack.get(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1)));
//return m_builder.CreateLoad(valuePtr);
return value;
}
void Stack::set(size_t _index, llvm::Value* _value)
{
m_builder.CreateStore(_value, m_arg);
m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
m_stack.set(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1)), _value);
}
void Stack::pop(size_t _count)
{
createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()});
// FIXME: Pop does not check for stack underflow but looks like not needed
// We should place stack.require() check and begining of every BB
m_stack.pop(m_builder.getInt64(_count));
}
void Stack::push(llvm::Value* _value)
{
m_builder.CreateStore(_value, m_arg);
m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg);
m_stack.push(_value);
}
size_t Stack::maxStackSize = 0;
}
}
}
@ -139,41 +180,6 @@ extern "C"
{
using namespace dev::eth::jit;
EXPORT bool stack_pop(Runtime* _rt, uint64_t _count)
{
auto& stack = _rt->getStack();
if (stack.size() < _count)
return false;
stack.erase(stack.end() - _count, stack.end());
return true;
}
EXPORT void stack_push(Runtime* _rt, i256 const* _word)
{
auto& stack = _rt->getStack();
stack.push_back(*_word);
if (stack.size() > Stack::maxStackSize)
Stack::maxStackSize = stack.size();
}
EXPORT i256* stack_get(Runtime* _rt, uint64_t _index)
{
auto& stack = _rt->getStack();
return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr;
}
EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word)
{
auto& stack = _rt->getStack();
assert(_index < stack.size());
if (_index >= stack.size())
return;
*(stack.rbegin() + _index) = *_word;
}
EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value)
{
// It asumes all indexes are less than 2^64

15
evmjit/libevmjit/Stack.h

@ -1,6 +1,8 @@
#pragma once
#include "CompilerHelper.h"
#include <functional>
#include "Array.h"
namespace dev
{
@ -19,21 +21,22 @@ public:
void set(size_t _index, llvm::Value* _value);
void pop(size_t _count);
void push(llvm::Value* _value);
static size_t maxStackSize;
void free() { m_stack.free(); }
private:
llvm::Function* getPopFunc();
llvm::Function* getPushFunc();
llvm::Function* getGetFunc();
llvm::Function* getSetFunc();
RuntimeManager& m_runtimeManager;
llvm::Function* m_pop = nullptr;
llvm::Function* m_push;
llvm::Function* m_push = nullptr;
llvm::Function* m_get = nullptr;
llvm::Function* m_set;
llvm::Function* m_set = nullptr;
llvm::Value* m_arg;
Array m_stack;
};

6
evmjit/libevmjit/Type.cpp

@ -1,4 +1,7 @@
#include "Type.h"
#include <llvm/IR/MDBuilder.h>
#include "RuntimeManager.h"
namespace dev
@ -23,6 +26,7 @@ llvm::PointerType* Type::EnvPtr;
llvm::PointerType* Type::RuntimeDataPtr;
llvm::PointerType* Type::RuntimePtr;
llvm::ConstantInt* Constant::gasMax;
llvm::MDNode* Type::expectTrue;
void Type::init(llvm::LLVMContext& _context)
{
@ -46,6 +50,8 @@ void Type::init(llvm::LLVMContext& _context)
RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo();
Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits<int64_t>::max());
expectTrue = llvm::MDBuilder{_context}.createBranchWeights(1, 0);
}
}

3
evmjit/libevmjit/Type.h

@ -40,6 +40,9 @@ struct Type
static llvm::PointerType* RuntimeDataPtr;
static llvm::PointerType* RuntimePtr;
// TODO: Redesign static LLVM objects
static llvm::MDNode* expectTrue;
static void init(llvm::LLVMContext& _context);
};

22
evmjit/libevmjit/Utils.cpp

@ -1,13 +1,27 @@
#include "Utils.h"
#include <llvm/Support/Debug.h>
#include "BuildInfo.gen.h"
#if !defined(NDEBUG) // Debug
namespace dev
{
namespace eth
{
namespace jit
namespace evmjit
{
std::ostream& getLogStream(char const* _channel)
{
static std::ostream nullStream{nullptr};
#if LLVM_DEBUG
return (llvm::DebugFlag && llvm::isCurrentDebugType(_channel)) ? std::cerr : nullStream;
#else
return (void)_channel, nullStream;
#endif
}
}
}
#endif

36
evmjit/libevmjit/Utils.h

@ -2,23 +2,39 @@
#include <iostream>
#include "Common.h"
// The same as assert, but expression is always evaluated and result returned
#define CHECK(expr) (assert(expr), expr)
#if !defined(NDEBUG) // Debug
namespace dev
{
namespace eth
{
namespace jit
namespace evmjit
{
struct JIT: public NoteChannel { static const char* name() { return "JIT"; } };
std::ostream& getLogStream(char const* _channel);
}
}
//#define clog(CHANNEL) std::cerr
#define clog(CHANNEL) std::ostream(nullptr)
#define DLOG(CHANNEL) ::dev::evmjit::getLogStream(#CHANNEL)
// The same as assert, but expression is always evaluated and result returned
#define CHECK(expr) (assert(expr), expr)
#else // Release
namespace dev
{
namespace evmjit
{
struct Voider
{
void operator=(std::ostream const&) {}
};
}
}
}
#define DLOG(CHANNEL) true ? (void)0 : ::dev::evmjit::Voider{} = std::cerr
#endif

5
evmjit/libevmjit/interface.cpp

@ -5,11 +5,6 @@ extern "C"
using namespace dev::eth::jit;
#ifdef _MSC_VER
#define _ALLOW_KEYWORD_MACROS
#define noexcept throw()
#endif
EXPORT void* evmjit_create() noexcept
{
// TODO: Make sure ExecutionEngine constructor does not throw

111
libdevcore/Assertions.h

@ -0,0 +1,111 @@
/*
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 Assertions.h
* @author Christian <c@ethdev.com>
* @date 2015
*
* Assertion handling.
*/
#pragma once
#include "Exceptions.h"
#include "debugbreak.h"
namespace dev
{
#if defined(_MSC_VER)
#define ETH_FUNC __FUNCSIG__
#elif defined(__GNUC__)
#define ETH_FUNC __PRETTY_FUNCTION__
#else
#define ETH_FUNC __func__
#endif
#define asserts(A) ::dev::assertAux(A, #A, __LINE__, __FILE__, ETH_FUNC)
#define assertsEqual(A, B) ::dev::assertEqualAux(A, B, #A, #B, __LINE__, __FILE__, ETH_FUNC)
inline bool assertAux(bool _a, char const* _aStr, unsigned _line, char const* _file, char const* _func)
{
bool ret = _a;
if (!ret)
{
std::cerr << "Assertion failed:" << _aStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl;
#if ETH_DEBUG
debug_break();
#endif
}
return !ret;
}
template<class A, class B>
inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char const* _bStr, unsigned _line, char const* _file, char const* _func)
{
bool ret = _a == _b;
if (!ret)
{
std::cerr << "Assertion failed: " << _aStr << " == " << _bStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl;
std::cerr << " Fail equality: " << _a << "==" << _b << std::endl;
#if ETH_DEBUG
debug_break();
#endif
}
return !ret;
}
/// Assertion that throws an exception containing the given description if it is not met.
/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong.");
/// Do NOT supply an exception object as the second parameter.
#define assertThrow(_condition, _ExceptionType, _description) \
::dev::assertThrowAux<_ExceptionType>(_condition, _description, __LINE__, __FILE__, ETH_FUNC)
using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
template <class _ExceptionType>
inline void assertThrowAux(
bool _condition,
::std::string const& _errorDescription,
unsigned _line,
char const* _file,
char const* _function
)
{
if (!_condition)
::boost::throw_exception(
_ExceptionType() <<
::dev::errinfo_comment(_errorDescription) <<
::boost::throw_function(_function) <<
::boost::throw_file(_file) <<
::boost::throw_line(_line)
);
}
template <class _ExceptionType>
inline void assertThrowAux(
void const* _pointer,
::std::string const& _errorDescription,
unsigned _line,
char const* _file,
char const* _function
)
{
assertThrowAux<_ExceptionType>(_pointer != nullptr, _errorDescription, _line, _file, _function);
}
}

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.8.2";
char const* Version = "0.9.5";
}

47
libdevcore/Common.h

@ -44,7 +44,6 @@
#pragma warning(pop)
#pragma GCC diagnostic pop
#include "vector_ref.h"
#include "debugbreak.h"
// CryptoPP defines byte in the global namespace, so must we.
using byte = uint8_t;
@ -87,6 +86,7 @@ using strings = std::vector<std::string>;
// Fixed-length string types.
using string32 = std::array<char, 32>;
static const string32 ZeroString32 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
// Null/Invalid values for convenience.
static const u256 Invalid256 = ~(u256)0;
@ -134,45 +134,20 @@ private:
std::function<void(void)> m_f;
};
// Assertions...
#if defined(_MSC_VER)
#define ETH_FUNC __FUNCSIG__
#elif defined(__GNUC__)
#define ETH_FUNC __PRETTY_FUNCTION__
#else
#define ETH_FUNC __func__
#endif
#define asserts(A) ::dev::assertAux(A, #A, __LINE__, __FILE__, ETH_FUNC)
#define assertsEqual(A, B) ::dev::assertEqualAux(A, B, #A, #B, __LINE__, __FILE__, ETH_FUNC)
inline bool assertAux(bool _a, char const* _aStr, unsigned _line, char const* _file, char const* _func)
enum class WithExisting: int
{
bool ret = _a;
if (!ret)
{
std::cerr << "Assertion failed:" << _aStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl;
#if ETH_DEBUG
debug_break();
#endif
}
return !ret;
Trust = 0,
Verify,
Kill
};
}
template<class A, class B>
inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char const* _bStr, unsigned _line, char const* _file, char const* _func)
namespace std {
inline dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
{
bool ret = _a == _b;
if (!ret)
{
std::cerr << "Assertion failed: " << _aStr << " == " << _bStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl;
std::cerr << " Fail equality: " << _a << "==" << _b << std::endl;
#if ETH_DEBUG
debug_break();
#endif
}
return !ret;
return static_cast<dev::WithExisting>(max(static_cast<int>(_a), static_cast<int>(_b)));
}
}

8
libdevcore/CommonData.cpp

@ -39,7 +39,7 @@ std::string dev::escaped(std::string const& _s, bool _all)
ret += "\\\"";
else if (i == '\\' && !_all)
ret += "\\\\";
else if (prettyEscapes.count(i))
else if (prettyEscapes.count(i) && !_all)
{
ret += '\\';
ret += prettyEscapes.find(i)->second;
@ -78,7 +78,7 @@ int dev::fromHex(char _i)
BOOST_THROW_EXCEPTION(BadHexCharacter() << errinfo_invalidSymbol(_i));
}
bytes dev::fromHex(std::string const& _s, ThrowType _throw)
bytes dev::fromHex(std::string const& _s, WhenError _throw)
{
unsigned s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
@ -96,7 +96,7 @@ bytes dev::fromHex(std::string const& _s, ThrowType _throw)
#ifndef BOOST_NO_EXCEPTIONS
cwarn << boost::current_exception_diagnostic_information();
#endif
if (_throw == ThrowType::Throw)
if (_throw == WhenError::Throw)
throw;
}
for (unsigned i = s; i < _s.size(); i += 2)
@ -109,7 +109,7 @@ bytes dev::fromHex(std::string const& _s, ThrowType _throw)
#ifndef BOOST_NO_EXCEPTIONS
cwarn << boost::current_exception_diagnostic_information();
#endif
if (_throw == ThrowType::Throw)
if (_throw == WhenError::Throw)
throw;
}
return ret;

20
libdevcore/CommonData.h

@ -35,21 +35,22 @@ namespace dev
// String conversion functions, mainly to/from hex/nibble/byte representations.
enum class ThrowType
enum class WhenError
{
NoThrow = 0,
DontThrow = 0,
Throw = 1,
};
/// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte.
/// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte.
/// @example toHex("A\x69") == "4169"
template <class _T>
std::string toHex(_T const& _data, int _w = 2)
{
std::ostringstream ret;
unsigned ii = 0;
for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str();
}
@ -59,8 +60,8 @@ int fromHex(char _i);
/// Converts a (printable) ASCII hex string into the corresponding byte stream.
/// @example fromHex("41626261") == asBytes("Abba")
/// If _throw = ThrowType::NoThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception.
bytes fromHex(std::string const& _s, ThrowType _throw = ThrowType::NoThrow);
/// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception.
bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow);
#if 0
std::string toBase58(bytesConstRef _data);
@ -74,6 +75,13 @@ inline std::string asString(bytes const& _b)
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
}
/// Converts byte array ref to a string containing the same (binary) data. Unless
/// the byte array happens to contain ASCII data, this won't be printable.
inline std::string asString(bytesConstRef _b)
{
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
}
/// Converts a string to a byte array containing the string's (byte) data.
inline bytes asBytes(std::string const& _b)
{

2
libdevcore/CommonIO.cpp

@ -112,6 +112,6 @@ string dev::contentsString(std::string const& _file)
void dev::writeFile(std::string const& _file, bytesConstRef _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
ofstream(_file, ios::trunc|ios::binary).write((char const*)_data.data(), _data.size());
}

22
libdevcore/CommonIO.h

@ -35,6 +35,7 @@
#include <sstream>
#include <string>
#include <iostream>
#include <chrono>
#include "Common.h"
#include "Base64.h"
@ -75,6 +76,27 @@ template <class T, class U> inline std::ostream& operator<<(std::ostream& _out,
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e);
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p);
template <class T> inline std::string toString(std::chrono::time_point<T> const& _e, std::string _format = "")
{
unsigned long milliSecondsSinceEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(_e.time_since_epoch()).count();
auto const durationSinceEpoch = std::chrono::milliseconds(milliSecondsSinceEpoch);
std::chrono::time_point<std::chrono::system_clock> const tpAfterDuration(durationSinceEpoch);
tm timeValue;
auto time = std::chrono::system_clock::to_time_t(tpAfterDuration);
#ifdef _WIN32
gmtime_s(&timeValue, &time);
#else
gmtime_r(&time, &timeValue);
#endif
unsigned const millisRemainder = milliSecondsSinceEpoch % 1000;
char buffer[1024];
if (strftime(buffer, sizeof(buffer), _format.c_str(), &timeValue))
return std::string(buffer) + "." + (millisRemainder < 1 ? "000" : millisRemainder < 10 ? "00" : millisRemainder < 100 ? "0" : "") + std::to_string(millisRemainder) + "Z";
return std::string();
}
template <class S, class T>
inline S& streamout(S& _out, std::vector<T> const& _e)
{

18
libdevcore/CommonJS.cpp

@ -23,15 +23,17 @@
#include "CommonJS.h"
using namespace std;
namespace dev
{
bytes jsToBytes(std::string const& _s)
bytes jsToBytes(string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
return fromHex(_s.substr(2));
else if (_s.find_first_not_of("0123456789") == std::string::npos)
else if (_s.find_first_not_of("0123456789") == string::npos)
// Decimal
return toCompactBigEndian(bigint(_s));
else
@ -42,7 +44,7 @@ bytes padded(bytes _b, unsigned _l)
{
while (_b.size() < _l)
_b.insert(_b.begin(), 0);
return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
return asBytes(asString(_b).substr(_b.size() - max(_l, _l)));
}
bytes paddedRight(bytes _b, unsigned _l)
@ -54,7 +56,7 @@ bytes paddedRight(bytes _b, unsigned _l)
bytes unpadded(bytes _b)
{
auto p = asString(_b).find_last_not_of((char)0);
_b.resize(p == std::string::npos ? 0 : (p + 1));
_b.resize(p == string::npos ? 0 : (p + 1));
return _b;
}
@ -72,18 +74,18 @@ bytes unpadLeft(bytes _b)
return _b;
}
std::string fromRaw(h256 _n, unsigned* _inc)
string fromRaw(h256 _n, unsigned* _inc)
{
if (_n)
{
std::string s((char const*)_n.data(), 32);
string s((char const*)_n.data(), 32);
auto l = s.find_first_of('\0');
if (!l)
return "";
if (l != std::string::npos)
if (l != string::npos)
{
auto p = s.find_first_not_of('\0', l);
if (!(p == std::string::npos || (_inc && p == 31)))
if (!(p == string::npos || (_inc && p == 31)))
return "";
if (_inc)
*_inc = (byte)s[31];

41
libdevcore/CommonJS.h

@ -38,12 +38,24 @@ template <unsigned S> std::string toJS(FixedHash<S> const& _h)
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n)
{
return "0x" + toHex(toCompactBigEndian(_n));
std::string h = toHex(toCompactBigEndian(_n, 1));
// remove first 0, if it is necessary;
std::string res = h[0] != '0' ? h : h.substr(1);
return "0x" + res;
}
inline std::string toJS(dev::bytes const& _n)
inline std::string toJS(bytes const& _n, std::size_t _padding = 0)
{
return "0x" + dev::toHex(_n);
bytes n = _n;
n.resize(std::max<unsigned>(n.size(), _padding));
return "0x" + toHex(n);
}
template< typename T >std::string toJS( T const& i )
{
std::stringstream stream;
stream << "0x" << std::hex << i;
return stream.str();
}
/// Convert string to byte array. Input parameters can be hex or dec. Returns empty array if invalid input e.g neither dec or hex.
@ -74,7 +86,7 @@ template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
inline std::string jsToFixed(double _s)
{
return toJS(dev::u256(_s * (double)(dev::u256(1) << 128)));
return toJS(u256(_s * (double)(u256(1) << 128)));
}
template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> jsToInt(std::string const& _s)
@ -92,25 +104,16 @@ template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_i
inline u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); }
inline std::string jsToDecimal(std::string const& _s)
inline int jsToInt(std::string const& _s)
{
return dev::toString(jsToU256(_s));
if (_s.size() > 2 && _s.substr(0, 2).compare("0x") == 0)
return std::stoi(_s, nullptr, 16);
return std::stoi(_s, nullptr, 10);
}
inline std::string jsFromBinary(dev::bytes _s, unsigned _padding = 32)
{
_s.resize(std::max<unsigned>(_s.size(), _padding));
return "0x" + dev::toHex(_s);
}
inline std::string jsFromBinary(std::string const& _s, unsigned _padding = 32)
{
return jsFromBinary(asBytes(_s), _padding);
}
inline double jsFromFixed(std::string const& _s)
inline std::string jsToDecimal(std::string const& _s)
{
return (double)jsToU256(_s) / (double)(dev::u256(1) << 128);
return toString(jsToU256(_s));
}
}

4
libdevcore/Exceptions.h

@ -33,7 +33,7 @@ namespace dev
// base class for all exceptions
struct Exception: virtual std::exception, virtual boost::exception
{
Exception(std::string _message = {}): m_message(std::move(_message)) {}
Exception(std::string _message = std::string()): m_message(std::move(_message)) {}
const char* what() const noexcept override { return m_message.empty() ? std::exception::what() : m_message.c_str(); }
private:
@ -44,6 +44,8 @@ struct BadHexCharacter: virtual Exception {};
struct RLPException: virtual Exception {};
struct BadCast: virtual RLPException {};
struct BadRLP: virtual RLPException {};
struct OversizeRLP: virtual RLPException {};
struct UndersizeRLP: virtual RLPException {};
struct NoNetworking: virtual Exception {};
struct NoUPnPDevice: virtual Exception {};
struct RootNotFound: virtual Exception {};

17
libdevcore/FixedHash.h

@ -87,6 +87,8 @@ public:
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
bool operator<(FixedHash const& _c) const { for (unsigned i = 0; i < N; ++i) if (m_data[i] < _c.m_data[i]) return true; else if (m_data[i] > _c.m_data[i]) return false; return false; }
bool operator>=(FixedHash const& _c) const { return !operator<(_c); }
bool operator<=(FixedHash const& _c) const { return operator==(_c) || operator<(_c); }
bool operator>(FixedHash const& _c) const { return !operator<=(_c); }
// The obvious binary operators.
FixedHash& operator^=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; }
@ -139,6 +141,7 @@ public:
return ret;
}
/// @returns a random valued object.
static FixedHash random() { return random(s_fixedHashEngine); }
/// A generic std::hash compatible function object.
@ -154,25 +157,17 @@ public:
}
};
inline FixedHash<32> bloom() const
{
FixedHash<32> ret;
for (auto i: m_data)
ret[i / 8] |= 1 << (i % 8);
return ret;
}
template <unsigned P, unsigned M> inline FixedHash& shiftBloom(FixedHash<M> const& _h)
{
return (*this |= _h.template nbloom<P, N>());
return (*this |= _h.template bloom<P, N>());
}
template <unsigned P, unsigned M> inline bool containsBloom(FixedHash<M> const& _h)
{
return contains(_h.template nbloom<P, N>());
return contains(_h.template bloom<P, N>());
}
template <unsigned P, unsigned M> inline FixedHash<M> nbloom() const
template <unsigned P, unsigned M> inline FixedHash<M> bloom() const
{
static const unsigned c_bloomBits = M * 8;
unsigned mask = c_bloomBits - 1;

31
libdevcore/RLP.cpp

@ -26,12 +26,31 @@ using namespace dev;
bytes dev::RLPNull = rlp("");
bytes dev::RLPEmptyList = rlpList();
RLP::RLP(bytesConstRef _d, Strictness _s):
m_data(_d)
{
if ((_s & FailIfTooBig) && actualSize() < _d.size())
{
if (_s & ThrowOnFail)
BOOST_THROW_EXCEPTION(OversizeRLP());
else
m_data.reset();
}
if ((_s & FailIfTooSmall) && actualSize() > _d.size())
{
if (_s & ThrowOnFail)
BOOST_THROW_EXCEPTION(UndersizeRLP());
else
m_data.reset();
}
}
RLP::iterator& RLP::iterator::operator++()
{
if (m_remaining)
{
m_lastItem.retarget(m_lastItem.next().data(), m_remaining);
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize());
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem, ThrowOnFail | FailIfTooSmall).actualSize());
m_remaining -= std::min<unsigned>(m_remaining, m_lastItem.size());
}
else
@ -44,7 +63,7 @@ RLP::iterator::iterator(RLP const& _parent, bool _begin)
if (_begin && _parent.isList())
{
auto pl = _parent.payload();
m_lastItem = pl.cropped(0, RLP(pl).actualSize());
m_lastItem = pl.cropped(0, RLP(pl, ThrowOnFail | FailIfTooSmall).actualSize());
m_remaining = pl.size() - m_lastItem.size();
}
else
@ -58,17 +77,17 @@ RLP RLP::operator[](unsigned _i) const
{
if (_i < m_lastIndex)
{
m_lastEnd = RLP(payload()).actualSize();
m_lastEnd = RLP(payload(), ThrowOnFail | FailIfTooSmall).actualSize();
m_lastItem = payload().cropped(0, m_lastEnd);
m_lastIndex = 0;
}
for (; m_lastIndex < _i && m_lastItem.size(); ++m_lastIndex)
{
m_lastItem = payload().cropped(m_lastEnd);
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize());
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem, ThrowOnFail | FailIfTooSmall).actualSize());
m_lastEnd += m_lastItem.size();
}
return RLP(m_lastItem);
return RLP(m_lastItem, ThrowOnFail | FailIfTooSmall);
}
RLPs RLP::toList() const
@ -154,7 +173,7 @@ unsigned RLP::items() const
bytesConstRef d = payload().cropped(0, length());
unsigned i = 0;
for (; d.size(); ++i)
d = d.cropped(RLP(d).actualSize());
d = d.cropped(RLP(d, ThrowOnFail | FailIfTooSmall).actualSize());
return i;
}
return 0;

34
libdevcore/RLP.h

@ -62,20 +62,34 @@ static const byte c_rlpListIndLenZero = c_rlpListStart + c_rlpListImmLenCount -
class RLP
{
public:
/// Conversion flags
enum
{
AllowNonCanon = 1,
ThrowOnFail = 4,
FailIfTooBig = 8,
FailIfTooSmall = 16,
Strict = ThrowOnFail | FailIfTooBig,
VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall,
LaisezFaire = AllowNonCanon
};
using Strictness = int;
/// Construct a null node.
RLP() {}
/// Construct a node of value given in the bytes.
explicit RLP(bytesConstRef _d): m_data(_d) {}
explicit RLP(bytesConstRef _d, Strictness _s = VeryStrict);
/// Construct a node of value given in the bytes.
explicit RLP(bytes const& _d): m_data(&_d) {}
explicit RLP(bytes const& _d, Strictness _s = VeryStrict): RLP(&_d, _s) {}
/// Construct a node to read RLP data in the bytes given.
RLP(byte const* _b, unsigned _s): m_data(bytesConstRef(_b, _s)) {}
RLP(byte const* _b, unsigned _s, Strictness _st = VeryStrict): RLP(bytesConstRef(_b, _s), _st) {}
/// Construct a node to read RLP data in the string.
explicit RLP(std::string const& _s): m_data(bytesConstRef((byte const*)_s.data(), _s.size())) {}
explicit RLP(std::string const& _s, Strictness _st = VeryStrict): RLP(bytesConstRef((byte const*)_s.data(), _s.size()), _st) {}
/// The bare data of the RLP.
bytesConstRef data() const { return m_data; }
@ -236,18 +250,6 @@ public:
return ret;
}
/// Int conversion flags
enum
{
AllowNonCanon = 1,
ThrowOnFail = 4,
FailIfTooBig = 8,
FailIfTooSmall = 16,
Strict = ThrowOnFail | FailIfTooBig,
VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall,
LaisezFaire = AllowNonCanon
};
/// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string.
template <class _T = unsigned> _T toInt(int _flags = Strict) const
{

38
libdevcore/StructuredLogger.cpp

@ -22,36 +22,26 @@
*/
#include "StructuredLogger.h"
#include <ctime>
#include <boost/asio/ip/tcp.hpp>
#include <json/json.h>
#include <libdevcore/CommonIO.h>
#include "Guards.h"
namespace ba = boost::asio;
using namespace std;
namespace dev
{
string StructuredLogger::timePointToString(chrono::system_clock::time_point const& _ts)
{
// not using C++11 std::put_time due to gcc bug
// http://stackoverflow.com/questions/14136833/stdput-time-implementation-status-in-gcc
char buffer[64];
time_t time = chrono::system_clock::to_time_t(_ts);
tm* ptm = localtime(&time);
if (strftime(buffer, sizeof(buffer), get().m_timeFormat.c_str(), ptm))
return string(buffer);
return "";
}
void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const
{
Json::Value event;
static Mutex s_lock;
Json::FastWriter fastWriter;
Guard l(s_lock);
event[_name] = _value;
cout << event << endl << flush;
cout << fastWriter.write(event) << endl;
}
void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion)
@ -61,7 +51,7 @@ void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersi
Json::Value event;
event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion);
event["ts"] = timePointToString(std::chrono::system_clock::now());
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "starting");
}
@ -74,7 +64,7 @@ void StructuredLogger::stopping(string const& _clientImpl, const char* _ethVersi
Json::Value event;
event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion);
event["ts"] = timePointToString(std::chrono::system_clock::now());
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "stopping");
}
@ -96,7 +86,7 @@ void StructuredLogger::p2pConnected(
event["remote_addr"] = addrStream.str();
event["remote_id"] = _id;
event["num_connections"] = Json::Value(_numConnections);
event["ts"] = timePointToString(_ts);
event["ts"] = dev::toString(_ts, get().m_timeFormat.c_str());
get().outputJson(event, "p2p.connected");
}
@ -112,7 +102,7 @@ void StructuredLogger::p2pDisconnected(string const& _id, bi::tcp::endpoint cons
event["remote_addr"] = addrStream.str();
event["remote_id"] = _id;
event["num_connections"] = Json::Value(_numConnections);
event["ts"] = timePointToString(chrono::system_clock::now());
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "p2p.disconnected");
}
@ -130,7 +120,7 @@ void StructuredLogger::minedNewBlock(
event["block_hash"] = _hash;
event["block_number"] = _blockNumber;
event["chain_head_hash"] = _chainHeadHash;
event["ts"] = timePointToString(std::chrono::system_clock::now());
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
event["block_prev_hash"] = _prevHash;
get().outputJson(event, "eth.miner.new_block");
@ -151,7 +141,7 @@ void StructuredLogger::chainReceivedNewBlock(
event["block_number"] = _blockNumber;
event["chain_head_hash"] = _chainHeadHash;
event["remote_id"] = _remoteID;
event["ts"] = timePointToString(chrono::system_clock::now());
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
event["block_prev_hash"] = _prevHash;
get().outputJson(event, "eth.chain.received.new_block");
@ -170,7 +160,7 @@ void StructuredLogger::chainNewHead(
event["block_hash"] = _hash;
event["block_number"] = _blockNumber;
event["chain_head_hash"] = _chainHeadHash;
event["ts"] = timePointToString(chrono::system_clock::now());
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
event["block_prev_hash"] = _prevHash;
get().outputJson(event, "eth.miner.new_block");
@ -184,7 +174,7 @@ void StructuredLogger::transactionReceived(string const& _hash, string const& _r
Json::Value event;
event["tx_hash"] = _hash;
event["remote_id"] = _remoteId;
event["ts"] = timePointToString(chrono::system_clock::now());
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "eth.tx.received");
}

13
libdevcore/StructuredLogger.h

@ -27,9 +27,10 @@
#include <string>
#include <chrono>
#include <libp2p/Network.h>
namespace Json { class Value; }
namespace boost { namespace asio { namespace ip { template<class T>class basic_endpoint; class tcp; }}}
namespace bi = boost::asio::ip;
namespace dev
{
@ -61,12 +62,16 @@ public:
static void stopping(std::string const& _clientImpl, const char* _ethVersion);
static void p2pConnected(
std::string const& _id,
bi::tcp::endpoint const& _addr,
bi::basic_endpoint<bi::tcp> const& _addr,
std::chrono::system_clock::time_point const& _ts,
std::string const& _remoteVersion,
unsigned int _numConnections
);
static void p2pDisconnected(std::string const& _id, bi::tcp::endpoint const& _addr, unsigned int _numConnections);
static void p2pDisconnected(
std::string const& _id,
bi::basic_endpoint<bi::tcp> const& _addr,
unsigned int _numConnections
);
static void minedNewBlock(
std::string const& _hash,
std::string const& _blockNumber,
@ -93,8 +98,6 @@ private:
StructuredLogger(StructuredLogger const&) = delete;
void operator=(StructuredLogger const&) = delete;
/// @returns a string representation of a timepoint
static std::string timePointToString(std::chrono::system_clock::time_point const& _ts);
void outputJson(Json::Value const& _value, std::string const& _name) const;
bool m_enabled = false;

5
libdevcore/vector_ref.h

@ -39,8 +39,9 @@ public:
size_t size() const { return m_count; }
bool empty() const { return !m_count; }
vector_ref<_T> next() const { return vector_ref<_T>(m_data + m_count, m_count); }
vector_ref<_T> cropped(size_t _begin, size_t _count = ~size_t(0)) const { if (m_data && _begin + std::max(size_t(0), _count) <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); }
void retarget(_T const* _d, size_t _s) { m_data = _d; m_count = _s; }
vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); }
vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); }
void retarget(_T* _d, size_t _s) { m_data = _d; m_count = _s; }
void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); }
void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }

66
libdevcrypto/Common.cpp

@ -15,8 +15,8 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.cpp
* @author Gav Wood <i@gavwood.com>
* @author Alex Leverington <nessence@gmail.com>
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
@ -82,6 +82,22 @@ bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
return true;
}
void dev::encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher)
{
bytes io = _plain.toBytes();
s_secp256k1.encryptECIES(_k, io);
o_cipher = std::move(io);
}
bool dev::decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
{
bytes io = _cipher.toBytes();
if (!s_secp256k1.decryptECIES(_k, io))
return false;
o_plaintext = std::move(io);
return true;
}
void dev::encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
{
// TOOD: @alex @subtly do this properly.
@ -94,6 +110,54 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
return decrypt(_k, _cipher, o_plain);
}
h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
{
h128 iv(Nonce::get());
return encryptSymNoAuth(_k, _plain, o_cipher, iv);
}
h128 dev::encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv)
{
o_cipher.resize(_plain.size());
const int c_aesKeyLen = 16;
SecByteBlock key(_k.data(), c_aesKeyLen);
try
{
CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), _iv.data());
e.ProcessData(o_cipher.data(), _plain.data(), _plain.size());
return _iv;
}
catch (CryptoPP::Exception& _e)
{
cerr << _e.what() << endl;
o_cipher.resize(0);
return h128();
}
}
bool dev::decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext)
{
o_plaintext.resize(_cipher.size());
const size_t c_aesKeyLen = 16;
SecByteBlock key(_k.data(), c_aesKeyLen);
try
{
CTR_Mode<AES>::Decryption d;
d.SetKeyWithIV(key, key.size(), _iv.data());
d.ProcessData(o_plaintext.data(), _cipher.data(), _cipher.size());
return true;
}
catch (CryptoPP::Exception& _e)
{
cerr << _e.what() << endl;
o_plaintext.resize(0);
return false;
}
}
Public dev::recover(Signature const& _sig, h256 const& _message)
{
return s_secp256k1.recover(_sig, _message.ref());

21
libdevcrypto/Common.h

@ -15,8 +15,8 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.h
* @author Gav Wood <i@gavwood.com>
* @author Alex Leverington <nessence@gmail.com>
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Ethereum-specific data structures & algorithms.
@ -45,7 +45,7 @@ using Signature = h520;
struct SignatureStruct
{
SignatureStruct() {}
SignatureStruct() = default;
SignatureStruct(Signature const& _s) { *(h520*)this = _s; }
SignatureStruct(h256 const& _r, h256 const& _s, byte _v): r(_r), s(_s), v(_v) {}
operator Signature() const { return *(h520 const*)this; }
@ -55,7 +55,7 @@ struct SignatureStruct
h256 r;
h256 s;
byte v;
byte v = 0;
};
/// An Ethereum address: 20 bytes.
@ -96,6 +96,21 @@ void encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Symmetric decryption.
bool decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypt payload using ECIES standard with AES128-CTR.
void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Decrypt payload using ECIES standard with AES128-CTR.
bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypts payload with random IV/ctr using AES128-CTR.
h128 encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Encrypts payload with specified IV/ctr using AES128-CTR.
h128 encryptSymNoAuth(Secret const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv);
/// Decrypts payload with specified IV/ctr.
bool decryptSymNoAuth(Secret const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext);
/// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash);

125
libdevcrypto/CryptoPP.cpp

@ -19,8 +19,10 @@
* @date 2014
*/
#include "CryptoPP.h"
#include <libdevcore/Guards.h>
#include <libdevcore/Assertions.h>
#include "ECDHE.h"
#include "CryptoPP.h"
using namespace std;
using namespace dev;
@ -31,6 +33,119 @@ static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes.");
static_assert(dev::Public::size == 64, "Public key must be 64 bytes.");
static_assert(dev::Signature::size == 65, "Signature must be 65 bytes.");
bytes Secp256k1::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen)
{
// interop w/go ecies implementation
// for sha3, blocksize is 136 bytes
// for sha256, blocksize is 64 bytes
auto reps = ((kdByteLen + 7) * 8) / (64 * 8);
bytes ctr({0, 0, 0, 1});
bytes k;
CryptoPP::SHA256 ctx;
for (unsigned i = 0; i <= reps; i++)
{
ctx.Update(ctr.data(), ctr.size());
ctx.Update(_z.data(), Secret::size);
ctx.Update(_s1.data(), _s1.size());
// append hash to k
bytes digest(32);
ctx.Final(digest.data());
ctx.Restart();
k.reserve(k.size() + h256::size);
move(digest.begin(), digest.end(), back_inserter(k));
if (++ctr[3] || ++ctr[2] || ++ctr[1] || ++ctr[0])
continue;
}
k.resize(kdByteLen);
return move(k);
}
void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher)
{
// interop w/go ecies implementation
auto r = KeyPair::create();
h256 z;
ecdh::agree(r.sec(), _k, z);
auto key = eciesKDF(z, bytes(), 32);
bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16);
CryptoPP::SHA256 ctx;
ctx.Update(mKeyMaterial.data(), mKeyMaterial.size());
bytes mKey(32);
ctx.Final(mKey.data());
bytes cipherText;
encryptSymNoAuth(*(Secret*)eKey.data(), bytesConstRef(&io_cipher), cipherText, h128());
if (cipherText.empty())
return;
bytes msg(1 + Public::size + h128::size + cipherText.size() + 32);
msg[0] = 0x04;
r.pub().ref().copyTo(bytesRef(&msg).cropped(1, Public::size));
bytesRef msgCipherRef = bytesRef(&msg).cropped(1 + Public::size + h128::size, cipherText.size());
bytesConstRef(&cipherText).copyTo(msgCipherRef);
// tag message
CryptoPP::HMAC<SHA256> hmacctx(mKey.data(), mKey.size());
bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size());
hmacctx.Update(cipherWithIV.data(), cipherWithIV.size());
hmacctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size());
io_cipher.resize(msg.size());
io_cipher.swap(msg);
}
bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text)
{
// interop w/go ecies implementation
// io_cipher[0] must be 2, 3, or 4, else invalidpublickey
if (io_text[0] < 2 || io_text[0] > 4)
// invalid message: publickey
return false;
if (io_text.size() < (1 + Public::size + h128::size + 1 + h256::size))
// invalid message: length
return false;
h256 z;
ecdh::agree(_k, *(Public*)(io_text.data()+1), z);
auto key = eciesKDF(z, bytes(), 64);
bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16);
bytes mKey(32);
CryptoPP::SHA256 ctx;
ctx.Update(mKeyMaterial.data(), mKeyMaterial.size());
ctx.Final(mKey.data());
bytes plain;
size_t cipherLen = io_text.size() - 1 - Public::size - h128::size - h256::size;
bytesConstRef cipherWithIV(io_text.data() + 1 + Public::size, h128::size + cipherLen);
bytesConstRef cipherIV = cipherWithIV.cropped(0, h128::size);
bytesConstRef cipherNoIV = cipherWithIV.cropped(h128::size, cipherLen);
bytesConstRef msgMac(cipherNoIV.data() + cipherLen, h256::size);
h128 iv(cipherIV.toBytes());
// verify tag
CryptoPP::HMAC<SHA256> hmacctx(mKey.data(), mKey.size());
hmacctx.Update(cipherWithIV.data(), cipherWithIV.size());
h256 mac;
hmacctx.Final(mac.data());
for (unsigned i = 0; i < h256::size; i++)
if (mac[i] != msgMac[i])
return false;
decryptSymNoAuth(*(Secret*)eKey.data(), iv, cipherNoIV, plain);
io_text.resize(plain.size());
io_text.swap(plain);
return true;
}
void Secp256k1::encrypt(Public const& _k, bytes& io_cipher)
{
ECIES<ECP>::Encryptor e;
@ -199,13 +314,13 @@ bool Secp256k1::verifySecret(Secret const& _s, Public& _p)
void Secp256k1::agree(Secret const& _s, Public const& _r, h256& o_s)
{
(void)o_s;
(void)_s;
ECDH<ECP>::Domain d(m_oid);
// TODO: mutex ASN1::secp256k1() singleton
// Creating Domain is non-const for m_oid and m_oid is not thread-safe
ECDH<ECP>::Domain d(ASN1::secp256k1());
assert(d.AgreedValueLength() == sizeof(o_s));
byte remote[65] = {0x04};
memcpy(&remote[1], _r.data(), 64);
assert(d.Agree(o_s.data(), _s.data(), remote));
d.Agree(o_s.data(), _s.data(), remote);
}
void Secp256k1::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p)

14
libdevcrypto/CryptoPP.h

@ -65,6 +65,7 @@ inline Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.
/**
* CryptoPP secp256k1 algorithms.
* @todo Collect ECIES methods into class.
*/
class Secp256k1
{
@ -75,12 +76,21 @@ public:
void toPublic(Secret const& _s, Public& o_public) { exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public); }
/// Encrypts text (replace input).
/// Encrypts text (replace input). (ECIES w/XOR-SHA1)
void encrypt(Public const& _k, bytes& io_cipher);
/// Decrypts text (replace input).
/// Decrypts text (replace input). (ECIES w/XOR-SHA1)
void decrypt(Secret const& _k, bytes& io_text);
/// Encrypts text (replace input). (ECIES w/AES128-CTR-SHA256)
void encryptECIES(Public const& _k, bytes& io_cipher);
/// Decrypts text (replace input). (ECIES w/AES128-CTR-SHA256)
bool decryptECIES(Secret const& _k, bytes& io_text);
/// Key derivation function used by encryptECIES and decryptECIES.
bytes eciesKDF(Secret _z, bytes _s1, unsigned kdBitLen = 256);
/// @returns siganture of message.
Signature sign(Secret const& _k, bytesConstRef _message);

7
libdevcrypto/ECDHE.cpp

@ -29,7 +29,12 @@ using namespace dev::crypto;
static Secp256k1 s_secp256k1;
void ECDHE::agree(Public const& _remote, Secret& o_sharedSecret)
void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, h256& o_s)
{
s_secp256k1.agree(_s, _r, o_s);
}
void ECDHE::agree(Public const& _remote, Secret& o_sharedSecret) const
{
if (m_remoteEphemeral)
// agreement can only occur once

17
libdevcrypto/ECDHE.h

@ -48,6 +48,11 @@ private:
std::map<Address,AliasSession> m_sessions;
Secret m_secret;
};
namespace ecdh
{
void agree(Secret const& _s, Public const& _r, h256& o_s);
}
/**
* @brief Derive DH shared secret from EC keypairs.
@ -62,12 +67,14 @@ public:
/// Public key sent to remote.
Public pubkey() { return m_ephemeral.pub(); }
Secret seckey() { return m_ephemeral.sec(); }
/// Input public key for dh agreement, output generated shared secret.
void agree(Public const& _remoteEphemeral, Secret& o_sharedSecret);
void agree(Public const& _remoteEphemeral, Secret& o_sharedSecret) const;
protected:
KeyPair m_ephemeral; ///< Ephemeral keypair; generated.
Public m_remoteEphemeral; ///< Public key of remote; parameter.
KeyPair m_ephemeral; ///< Ephemeral keypair; generated.
mutable Public m_remoteEphemeral; ///< Public key of remote; parameter. Set once when agree is called, otherwise immutable.
};
/**
@ -80,10 +87,10 @@ class ECDHEKeyExchange: private ECDHE
{
public:
/// Exchange with unknown remote (pass public key for ingress exchange)
ECDHEKeyExchange(Alias& _k): m_alias(_k) {};
ECDHEKeyExchange(Alias& _k): m_alias(_k) {}
/// Exchange with known remote
ECDHEKeyExchange(Alias& _k, AliasSession _known): m_alias(_k), m_known(_known) {};
ECDHEKeyExchange(Alias& _k, AliasSession _known): m_alias(_k), m_known(_known) {}
/// Provide public key for dh agreement to generate shared secret.
void agree(Public const& _remoteEphemeral);

9
libdevcrypto/FileSystem.cpp

@ -32,12 +32,15 @@
using namespace std;
using namespace dev;
std::string dev::getDataDir()
std::string dev::getDataDir(std::string _prefix)
{
if (_prefix.empty())
_prefix = "ethereum";
#ifdef _WIN32
_prefix[0] = toupper(_prefix[0]);
char path[1024] = "";
if (SHGetSpecialFolderPathA(NULL, path, CSIDL_APPDATA, true))
return (boost::filesystem::path(path) / "Ethereum").string();
return (boost::filesystem::path(path) / _prefix).string();
else
{
#ifndef _MSC_VER // todo?
@ -57,7 +60,7 @@ std::string dev::getDataDir()
// This eventually needs to be put in proper wrapper (to support sandboxing)
return (dataDirPath / "Library/Application Support/Ethereum").string();
#else
return (dataDirPath / ".ethereum").string();
return (dataDirPath / ("." + _prefix)).string();
#endif
#endif
}

2
libdevcrypto/FileSystem.h

@ -30,6 +30,6 @@ namespace dev
{
/// @returns the path for user data.
std::string getDataDir();
std::string getDataDir(std::string _prefix = "ethereum");
}

2
libdevcrypto/MemoryDB.h

@ -32,8 +32,10 @@ namespace dev
{
struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; };
struct DBWarn: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 1; };
#define dbdebug clog(DBChannel)
#define dbwarn clog(DBWarn)
class MemoryDB
{

8
libethash/CMakeLists.txt

@ -2,7 +2,6 @@ set(LIBRARY ethash)
if (CPPETHEREUM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
#else ()
endif ()
set(CMAKE_BUILD_TYPE Release)
@ -13,6 +12,7 @@ endif()
set(FILES util.c
util.h
io.c
internal.c
ethash.h
endian.h
@ -20,6 +20,12 @@ set(FILES util.c
fnv.h
data_sizes.h)
if (MSVC)
list(APPEND FILES io_win32.c)
else()
list(APPEND FILES io_posix.c)
endif()
if (NOT CRYPTOPP_FOUND)
find_package(CryptoPP 5.6.2)
endif()

967
libethash/data_sizes.h

@ -20,8 +20,6 @@
* @date 2015
*/
// TODO: Update this after ~3.5 years
#pragma once
#include <stdint.h>
@ -33,213 +31,780 @@ extern "C" {
#include <stdint.h>
// 500 Epochs worth of tabulated DAG sizes (~3.5 Years)
// 2048 Epochs (~20 years) worth of tabulated DAG sizes
// Generated with the following Mathematica Code:
// GetDataSizes[n_] := Module[{
// DAGSizeBytesInit = 2^30,
// MixBytes = 128,
// DAGGrowth = 113000000,
// GetCacheSizes[n_] := Module[{
// CacheSizeBytesInit = 2^24,
// CacheGrowth = 2^17,
// HashBytes = 64,
// j = 0},
// Reap[
// While[j < n,
// Module[{i =
// Floor[(DAGSizeBytesInit + DAGGrowth * j) / MixBytes]},
// While[! PrimeQ[i], i--];
// Sow[i*MixBytes]; j++]]]][[2]][[1]]
static const size_t dag_sizes[] = {
1073739904U, 1186739584U, 1299741568U, 1412741248U, 1525741696U,
1638736768U, 1751741312U, 1864740736U, 1977740672U, 2090740864U,
2203740544U, 2316741248U, 2429739392U, 2542740352U, 2655741824U,
2768739712U, 2881740416U, 2994741632U, 3107740544U, 3220741504U,
3333738112U, 3446741632U, 3559741312U, 3672740224U, 3785740928U,
3898738304U, 4011741824U, 4124739712U, 4237735808U, 4350740864U,
4463741824U, 4576741504U, 4689741184U, 4802739328U, 4915741568U,
5028740224U, 5141740672U, 5254738304U, 5367741824U, 5480737664U,
5593738112U, 5706741632U, 5819740544U, 5932734592U, 6045739904U,
6158740096U, 6271740032U, 6384731776U, 6497732992U, 6610740352U,
6723741056U, 6836741504U, 6949740416U, 7062740096U, 7175741824U,
7288740224U, 7401741184U, 7514741632U, 7627741568U, 7740739712U,
7853739136U, 7966740352U, 8079741568U, 8192739712U, 8305738624U,
8418740864U, 8531740288U, 8644740736U, 8757735808U, 8870738816U,
8983739264U, 9096740992U, 9209740928U, 9322739584U, 9435741824U,
9548741504U, 9661739392U, 9774738304U, 9887741312U, 10000738688U,
10113739136U, 10226741632U, 10339739776U, 10452741248U, 10565740928U,
10678736512U, 10791734656U, 10904741248U, 11017738112U, 11130741632U,
11243741312U, 11356739456U, 11469740416U, 11582734976U, 11695739008U,
11808741248U, 11921734784U, 12034739072U, 12147741568U, 12260737408U,
12373741696U, 12486738304U, 12599740544U, 12712740224U, 12825741184U,
12938736256U, 13051741312U, 13164737408U, 13277738368U, 13390738048U,
13503741824U, 13616741504U, 13729737088U, 13842740096U, 13955741312U,
14068741504U, 14181740416U, 14294741632U, 14407739776U, 14520740224U,
14633740928U, 14746736512U, 14859741824U, 14972740736U, 15085740928U,
15198738304U, 15311732096U, 15424740736U, 15537739904U, 15650741632U,
15763741568U, 15876737152U, 15989741696U, 16102740608U, 16215741056U,
16328741248U, 16441740416U, 16554737792U, 16667740288U, 16780740992U,
16893738112U, 17006741632U, 17119739008U, 17232735616U, 17345739392U,
17458740352U, 17571736192U, 17684739712U, 17797739392U, 17910740096U,
18023741312U, 18136740736U, 18249738112U, 18362738816U, 18475735424U,
18588740224U, 18701738368U, 18814736768U, 18927737216U, 19040739968U,
19153739648U, 19266736768U, 19379737984U, 19492739456U, 19605738368U,
19718740352U, 19831741312U, 19944736384U, 20057741696U, 20170741376U,
20283741824U, 20396737408U, 20509741696U, 20622741376U, 20735739008U,
20848741504U, 20961740672U, 21074739328U, 21187740032U, 21300739456U,
21413741696U, 21526740608U, 21639741824U, 21752737408U, 21865741696U,
21978741376U, 22091741824U, 22204738432U, 22317740672U, 22430740096U,
22543736704U, 22656741248U, 22769739904U, 22882739584U, 22995740288U,
23108740736U, 23221740928U, 23334741376U, 23447737216U, 23560740992U,
23673741184U, 23786740864U, 23899737728U, 24012741248U, 24125734784U,
24238736512U, 24351741824U, 24464740736U, 24577737088U, 24690741632U,
24803739776U, 24916740736U, 25029740416U, 25142740864U, 25255741568U,
25368741248U, 25481740672U, 25594741376U, 25707741568U, 25820741504U,
25933730432U, 26046739072U, 26159741824U, 26272741504U, 26385740672U,
26498740096U, 26611741568U, 26724740992U, 26837739904U, 26950735232U,
27063738496U, 27176741248U, 27289741184U, 27402740864U, 27515740544U,
27628737152U, 27741740672U, 27854741632U, 27967740544U, 28080739712U,
28193738368U, 28306741376U, 28419737728U, 28532739968U, 28645739648U,
28758740096U, 28871741312U, 28984739456U, 29097740416U, 29210740864U,
29323741312U, 29436740224U, 29549741696U, 29662738304U, 29775741568U,
29888741504U, 30001740928U, 30114737024U, 30227735168U, 30340737664U,
30453738368U, 30566737024U, 30679733632U, 30792740224U, 30905740928U,
31018740352U, 31131740032U, 31244738944U, 31357737344U, 31470741376U,
31583740544U, 31696740224U, 31809738112U, 31922739328U, 32035737472U,
32148740992U, 32261741696U, 32374740352U, 32487741824U, 32600740736U,
32713739648U, 32826740608U, 32939729792U, 33052740992U, 33165740672U,
33278739584U, 33391741312U, 33504739712U, 33617740928U, 33730740608U,
33843738496U, 33956739968U, 34069741696U, 34182739328U, 34295741824U,
34408739968U, 34521740672U, 34634736512U, 34747741568U, 34860741248U,
34973739392U, 35086738304U, 35199741056U, 35312736896U, 35425741184U,
35538741376U, 35651740288U, 35764737152U, 35877741184U, 35990739584U,
36103740544U, 36216740992U, 36329739392U, 36442737536U, 36555741568U,
36668740736U, 36781741184U, 36894737024U, 37007741312U, 37120739456U,
37233741184U, 37346736256U, 37459736192U, 37572734336U, 37685739904U,
37798740352U, 37911737728U, 38024741504U, 38137739648U, 38250740608U,
38363741824U, 38476740992U, 38589741184U, 38702740096U, 38815741312U,
38928741248U, 39041738368U, 39154739584U, 39267741824U, 39380739712U,
39493735808U, 39606741632U, 39719741312U, 39832741504U, 39945739648U,
40058740352U, 40171740032U, 40284740992U, 40397740672U, 40510740352U,
40623740288U, 40736738176U, 40849737856U, 40962741376U, 41075739776U,
41188737664U, 41301735808U, 41414738048U, 41527741312U, 41640740992U,
41753739904U, 41866739072U, 41979738496U, 42092740736U, 42205739648U,
42318740608U, 42431741312U, 42544738688U, 42657741184U, 42770738048U,
42883741568U, 42996741248U, 43109740928U, 43222736512U, 43335741056U,
43448730496U, 43561740416U, 43674741632U, 43787740544U, 43900741504U,
44013739648U, 44126740864U, 44239740544U, 44352741248U, 44465738368U,
44578735232U, 44691739264U, 44804741504U, 44917741696U, 45030741376U,
45143741824U, 45256740992U, 45369739136U, 45482740096U, 45595739776U,
45708739712U, 45821740672U, 45934741376U, 46047741056U, 46160741248U,
46273737088U, 46386740864U, 46499739008U, 46612739968U, 46725735296U,
46838740864U, 46951741568U, 47064737152U, 47177741696U, 47290741376U,
47403738752U, 47516741248U, 47629739648U, 47742741632U, 47855737984U,
47968740224U, 48081738368U, 48194741632U, 48307739264U, 48420739712U,
48533739136U, 48646738304U, 48759741824U, 48872741504U, 48985739392U,
49098741376U, 49211741056U, 49324740992U, 49437738368U, 49550740864U,
49663735424U, 49776737408U, 49889740672U, 50002738816U, 50115738752U,
50228739712U, 50341741696U, 50454736768U, 50567738752U, 50680739968U,
50793736832U, 50906734976U, 51019741568U, 51132739456U, 51245741696U,
51358741376U, 51471741056U, 51584738944U, 51697734272U, 51810739072U,
51923736448U, 52036740736U, 52149741184U, 52262737024U, 52375738496U,
52488740992U, 52601739136U, 52714740352U, 52827736448U, 52940738176U,
53053741696U, 53166740864U, 53279741824U, 53392741504U, 53505739136U,
53618739584U, 53731741312U, 53844741248U, 53957741696U, 54070741376U,
54183740288U, 54296741504U, 54409741696U, 54522739072U, 54635737472U,
54748741504U, 54861736064U, 54974740096U, 55087741568U, 55200733568U,
55313741696U, 55426734464U, 55539741056U, 55652741504U, 55765741184U,
55878741376U, 55991730304U, 56104740992U, 56217740672U, 56330731648U,
56443737472U, 56556724352U, 56669740672U, 56782739072U, 56895740032U,
57008741248U, 57121741696U, 57234740096U, 57347741312U, 57460741504U
// Reap[
// While[j < n,
// Module[{i =
// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]},
// While[! PrimeQ[i], i--];
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
static const uint64_t dag_sizes[2048] = {
1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U,
1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U,
1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U,
1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U,
1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U,
1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U,
1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U,
1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U,
1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U,
1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U,
1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U,
1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U,
1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U,
1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U,
1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U,
1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U,
1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U,
1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U,
1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U,
1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U,
1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U,
1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U,
1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U,
2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U,
2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U,
2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U,
2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U,
2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U,
2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U,
2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U,
2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U,
2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U,
2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U,
2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U,
2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U,
2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U,
2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U,
2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U,
2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U,
2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U,
2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U,
2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U,
2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U,
2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U,
2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U,
2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U,
3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U,
3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U,
3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U,
3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U,
3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U,
3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U,
3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U,
3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U,
3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U,
3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U,
3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U,
3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U,
3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U,
3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U,
3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U,
3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U,
3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U,
3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U,
3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U,
3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U,
3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U,
3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U,
3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U,
3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U,
4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U,
4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U,
4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U,
4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U,
4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U,
4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U,
4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U,
4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U,
4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U,
4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U,
4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U,
4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U,
4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U,
4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U,
4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U,
4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U,
4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U,
4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U,
4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U,
4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U,
4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U,
4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U,
4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U,
4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U,
5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U,
5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U,
5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U,
5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U,
5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U,
5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U,
5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U,
5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U,
5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U,
5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U,
5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U,
5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U,
5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U,
5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U,
5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U,
5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U,
5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U,
5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U,
5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U,
5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U,
5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U,
5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U,
5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U,
5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U,
6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U,
6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U,
6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U,
6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U,
6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U,
6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U,
6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U,
6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U,
6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U,
6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U,
6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U,
6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U,
6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U,
6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U,
6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U,
6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U,
6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U,
6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U,
6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U,
6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U,
6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U,
6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U,
6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U,
6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U,
7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U,
7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U,
7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U,
7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U,
7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U,
7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U,
7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U,
7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U,
7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U,
7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U,
7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U,
7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U,
7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U,
7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U,
7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U,
7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U,
7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U,
7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U,
7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U,
7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U,
7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U,
7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U,
7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U,
7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U,
8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U,
8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U,
8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U,
8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U,
8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U,
8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U,
8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U,
8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U,
8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U,
8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U,
8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U,
8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U,
8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U,
8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U,
8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U,
8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U,
8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U,
8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U,
8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U,
8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U,
8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U,
8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U,
8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U,
9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U,
9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U,
9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U,
9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U,
9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U,
9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U,
9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U,
9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U,
9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U,
9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U,
9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U,
9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U,
9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U,
9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U,
9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U,
9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U,
9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U,
9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U,
9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U,
9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U,
9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U,
9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U,
9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U,
9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U,
10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U,
10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U,
10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U,
10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U,
10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U,
10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U,
10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U,
10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U,
10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U,
10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U,
10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U,
10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U,
10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U,
10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U,
10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U,
10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U,
10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U,
10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U,
10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U,
10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U,
10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U,
10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U,
10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U,
10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U,
11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U,
11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U,
11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U,
11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U,
11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U,
11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U,
11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U,
11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U,
11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U,
11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U,
11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U,
11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U,
11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U,
11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U,
11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U,
11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U,
11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U,
11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U,
11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U,
11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U,
11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U,
11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U,
11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U,
11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U,
12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U,
12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U,
12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U,
12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U,
12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U,
12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U,
12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U,
12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U,
12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U,
12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U,
12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U,
12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U,
12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U,
12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U,
12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U,
12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U,
12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U,
12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U,
12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U,
12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U,
12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U,
12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U,
12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U,
12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U,
13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U,
13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U,
13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U,
13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U,
13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U,
13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U,
13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U,
13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U,
13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U,
13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U,
13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U,
13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U,
13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U,
13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U,
13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U,
13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U,
13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U,
13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U,
13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U,
13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U,
13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U,
13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U,
13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U,
13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U,
14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U,
14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U,
14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U,
14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U,
14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U,
14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U,
14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U,
14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U,
14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U,
14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U,
14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U,
14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U,
14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U,
14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U,
14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U,
14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U,
14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U,
14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U,
14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U,
14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U,
14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U,
14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U,
14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U,
14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U,
15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U,
15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U,
15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U,
15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U,
15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U,
15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U,
15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U,
15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U,
15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U,
15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U,
15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U,
15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U,
15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U,
15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U,
15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U,
15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U,
15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U,
15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U,
15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U,
15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U,
15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U,
15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U,
15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U,
16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U,
16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U,
16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U,
16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U,
16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U,
16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U,
16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U,
16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U,
16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U,
16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U,
16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U,
16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U,
16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U,
16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U,
16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U,
16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U,
16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U,
16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U,
16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U,
16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U,
16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U,
16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U,
16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U,
16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U,
17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U,
17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U,
17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U,
17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U,
17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U,
17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U,
17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U,
17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U,
17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U,
17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U,
17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U,
17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U,
17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U,
17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U,
17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U,
17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U,
17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U,
17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U,
17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U,
17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U,
17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U,
17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U,
17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U,
17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U,
18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U,
18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U,
18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U,
18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U,
18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U,
18228444544U, 18236833408U, 18245220736U
};
// 500 Epochs worth of tabulated DAG sizes (~3.5 Years)
// Generated with the following Mathematica Code:
// GetCacheSizes[n_] := Module[{
// DAGSizeBytesInit = 2^30,
// MixBytes = 128,
// DAGGrowth = 113000000,
// HashBytes = 64,
// DAGParents = 1024,
// j = 0},
// Reap[
// While[j < n,
// Module[{i = Floor[(DAGSizeBytesInit + DAGGrowth * j) / (DAGParents * HashBytes)]},
// While[! PrimeQ[i], i--];
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
const size_t cache_sizes[] = {
1048384U, 1158208U, 1268416U, 1377856U, 1489856U, 1599296U, 1710656U,
1820608U, 1930816U, 2041024U, 2151872U, 2261696U, 2371904U, 2482624U,
2593216U, 2703296U, 2814016U, 2924224U, 3034816U, 3144896U, 3255488U,
3365312U, 3475904U, 3586624U, 3696064U, 3806272U, 3917504U, 4027456U,
4138304U, 4248512U, 4359104U, 4469312U, 4579264U, 4689728U, 4797376U,
4909888U, 5020096U, 5131328U, 5241664U, 5351744U, 5461312U, 5572544U,
5683264U, 5793472U, 5903552U, 6014144U, 6121664U, 6235072U, 6344896U,
6454592U, 6565952U, 6675904U, 6786112U, 6896704U, 7006784U, 7117888U,
7228096U, 7338304U, 7448768U, 7557952U, 7669184U, 7779776U, 7889216U,
8000192U, 8110912U, 8220736U, 8331712U, 8441536U, 8552384U, 8662592U,
8772928U, 8883136U, 8993728U, 9103168U, 9214528U, 9323968U, 9434816U,
9545152U, 9655616U, 9766336U, 9876544U, 9986624U, 10097344U, 10207424U,
10316864U, 10427968U, 10538432U, 10649152U, 10758976U, 10869568U, 10979776U,
11089472U, 11200832U, 11309632U, 11420608U, 11531584U, 11641792U, 11751104U,
11862976U, 11973184U, 12083264U, 12193856U, 12304064U, 12414656U, 12524608U,
12635072U, 12745792U, 12855616U, 12965824U, 13076416U, 13187008U, 13297216U,
13407808U, 13518016U, 13627072U, 13738688U, 13848256U, 13959488U, 14069696U,
14180288U, 14290624U, 14399552U, 14511424U, 14621504U, 14732096U, 14841664U,
14951744U, 15062336U, 15172672U, 15283264U, 15393088U, 15504448U, 15614272U,
15723712U, 15834944U, 15945152U, 16055744U, 16165696U, 16277056U, 16387136U,
16494784U, 16607936U, 16718272U, 16828736U, 16938176U, 17048384U, 17159872U,
17266624U, 17380544U, 17490496U, 17600192U, 17711296U, 17821376U, 17931968U,
18041152U, 18152896U, 18261952U, 18373568U, 18483392U, 18594112U, 18703936U,
18814912U, 18924992U, 19034944U, 19145408U, 19256128U, 19366208U, 19477184U,
19587136U, 19696576U, 19808192U, 19916992U, 20028352U, 20137664U, 20249024U,
20358848U, 20470336U, 20580544U, 20689472U, 20801344U, 20911424U, 21020096U,
21130688U, 21242176U, 21352384U, 21462208U, 21573824U, 21683392U, 21794624U,
21904448U, 22013632U, 22125248U, 22235968U, 22344512U, 22456768U, 22566848U,
22677056U, 22786496U, 22897984U, 23008064U, 23118272U, 23228992U, 23338816U,
23449408U, 23560256U, 23670464U, 23780672U, 23891264U, 24001216U, 24110656U,
24221888U, 24332608U, 24442688U, 24552512U, 24662464U, 24773696U, 24884032U,
24994496U, 25105216U, 25215296U, 25324864U, 25435712U, 25546432U, 25655744U,
25767232U, 25876672U, 25986368U, 26098112U, 26207936U, 26318912U, 26428736U,
26539712U, 26650048U, 26760256U, 26869184U, 26979776U, 27091136U, 27201728U,
27311552U, 27422272U, 27532352U, 27642304U, 27752896U, 27863744U, 27973952U,
28082752U, 28194752U, 28305344U, 28415168U, 28524992U, 28636352U, 28746304U,
28857152U, 28967104U, 29077184U, 29187904U, 29298496U, 29408576U, 29518912U,
29628992U, 29739968U, 29850176U, 29960512U, 30070336U, 30180544U, 30290752U,
30398912U, 30512192U, 30622784U, 30732992U, 30842176U, 30953536U, 31063744U,
31174336U, 31284544U, 31395136U, 31504448U, 31615552U, 31725632U, 31835072U,
31946176U, 32057024U, 32167232U, 32277568U, 32387008U, 32497984U, 32608832U,
32719168U, 32829376U, 32939584U, 33050048U, 33160768U, 33271232U, 33381184U,
33491648U, 33601856U, 33712576U, 33822016U, 33932992U, 34042816U, 34153024U,
34263104U, 34373824U, 34485056U, 34594624U, 34704832U, 34816064U, 34926272U,
35036224U, 35146816U, 35255104U, 35367104U, 35478208U, 35588416U, 35698496U,
35808832U, 35918656U, 36029888U, 36139456U, 36250688U, 36360512U, 36471104U,
36581696U, 36691136U, 36802112U, 36912448U, 37022912U, 37132864U, 37242944U,
37354048U, 37464512U, 37574848U, 37684928U, 37794752U, 37904704U, 38015552U,
38125888U, 38236864U, 38345792U, 38457152U, 38567744U, 38678336U, 38787776U,
38897216U, 39009088U, 39117632U, 39230144U, 39340352U, 39450304U, 39560384U,
39671488U, 39781312U, 39891392U, 40002112U, 40112704U, 40223168U, 40332608U,
40443968U, 40553792U, 40664768U, 40774208U, 40884416U, 40993984U, 41105984U,
41215424U, 41326528U, 41436992U, 41546048U, 41655872U, 41768128U, 41878336U,
41988928U, 42098752U, 42209344U, 42319168U, 42429248U, 42540352U, 42649792U,
42761024U, 42871616U, 42981824U, 43092032U, 43201856U, 43312832U, 43423552U,
43533632U, 43643584U, 43753792U, 43864384U, 43974976U, 44084032U, 44195392U,
44306368U, 44415296U, 44526016U, 44637248U, 44746816U, 44858048U, 44967872U,
45078848U, 45188288U, 45299264U, 45409216U, 45518272U, 45630272U, 45740224U,
45850432U, 45960896U, 46069696U, 46182208U, 46292416U, 46402624U, 46512064U,
46623296U, 46733888U, 46843712U, 46953664U, 47065024U, 47175104U, 47285696U,
47395904U, 47506496U, 47615296U, 47726912U, 47837632U, 47947712U, 48055232U,
48168128U, 48277952U, 48387392U, 48499648U, 48609472U, 48720064U, 48830272U,
48940096U, 49050944U, 49160896U, 49271744U, 49381568U, 49492288U, 49602752U,
49712576U, 49822016U, 49934272U, 50042816U, 50154304U, 50264128U, 50374336U,
50484416U, 50596288U, 50706752U, 50816704U, 50927168U, 51035456U, 51146944U,
51258176U, 51366976U, 51477824U, 51589568U, 51699776U, 51809728U, 51920576U,
52030016U, 52140736U, 52251328U, 52361152U, 52470592U, 52582592U, 52691776U,
52803136U, 52912576U, 53020736U, 53132224U, 53242688U, 53354816U, 53465536U,
53575232U, 53685568U, 53796544U, 53906752U, 54016832U, 54126656U, 54236992U,
54347456U, 54457408U, 54569024U, 54679232U, 54789184U, 54899776U, 55008832U,
55119296U, 55231168U, 55341248U, 55451584U, 55562048U, 55672256U, 55782208U,
55893184U, 56002112U, 56113216U
// DataSetSizeBytesInit = 2^30,
// MixBytes = 128,
// DataSetGrowth = 2^23,
// HashBytes = 64,
// CacheMultiplier = 1024,
// j = 0},
// Reap[
// While[j < n,
// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]},
// While[! PrimeQ[i], i--];
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
const uint64_t cache_sizes[2048] = {
16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U,
17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U,
18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U,
19529408U, 19660096U, 19791424U, 19922752U, 20053952U, 20184896U, 20315968U,
20446912U, 20576576U, 20709184U, 20840384U, 20971072U, 21102272U, 21233216U,
21364544U, 21494848U, 21626816U, 21757376U, 21887552U, 22019392U, 22151104U,
22281536U, 22412224U, 22543936U, 22675264U, 22806464U, 22935872U, 23068096U,
23198272U, 23330752U, 23459008U, 23592512U, 23723968U, 23854912U, 23986112U,
24116672U, 24247616U, 24378688U, 24509504U, 24640832U, 24772544U, 24903488U,
25034432U, 25165376U, 25296704U, 25427392U, 25558592U, 25690048U, 25820096U,
25951936U, 26081728U, 26214208U, 26345024U, 26476096U, 26606656U, 26737472U,
26869184U, 26998208U, 27131584U, 27262528U, 27393728U, 27523904U, 27655744U,
27786688U, 27917888U, 28049344U, 28179904U, 28311488U, 28441792U, 28573504U,
28700864U, 28835648U, 28966208U, 29096768U, 29228608U, 29359808U, 29490752U,
29621824U, 29752256U, 29882816U, 30014912U, 30144448U, 30273728U, 30406976U,
30538432U, 30670784U, 30799936U, 30932672U, 31063744U, 31195072U, 31325248U,
31456192U, 31588288U, 31719232U, 31850432U, 31981504U, 32110784U, 32243392U,
32372672U, 32505664U, 32636608U, 32767808U, 32897344U, 33029824U, 33160768U,
33289664U, 33423296U, 33554368U, 33683648U, 33816512U, 33947456U, 34076992U,
34208704U, 34340032U, 34471744U, 34600256U, 34734016U, 34864576U, 34993984U,
35127104U, 35258176U, 35386688U, 35518528U, 35650624U, 35782336U, 35910976U,
36044608U, 36175808U, 36305728U, 36436672U, 36568384U, 36699968U, 36830656U,
36961984U, 37093312U, 37223488U, 37355072U, 37486528U, 37617472U, 37747904U,
37879232U, 38009792U, 38141888U, 38272448U, 38403392U, 38535104U, 38660672U,
38795584U, 38925632U, 39059264U, 39190336U, 39320768U, 39452096U, 39581632U,
39713984U, 39844928U, 39974848U, 40107968U, 40238144U, 40367168U, 40500032U,
40631744U, 40762816U, 40894144U, 41023552U, 41155904U, 41286208U, 41418304U,
41547712U, 41680448U, 41811904U, 41942848U, 42073792U, 42204992U, 42334912U,
42467008U, 42597824U, 42729152U, 42860096U, 42991552U, 43122368U, 43253696U,
43382848U, 43515712U, 43646912U, 43777088U, 43907648U, 44039104U, 44170432U,
44302144U, 44433344U, 44564288U, 44694976U, 44825152U, 44956864U, 45088448U,
45219008U, 45350464U, 45481024U, 45612608U, 45744064U, 45874496U, 46006208U,
46136768U, 46267712U, 46399424U, 46529344U, 46660672U, 46791488U, 46923328U,
47053504U, 47185856U, 47316928U, 47447872U, 47579072U, 47710144U, 47839936U,
47971648U, 48103232U, 48234176U, 48365248U, 48496192U, 48627136U, 48757312U,
48889664U, 49020736U, 49149248U, 49283008U, 49413824U, 49545152U, 49675712U,
49807168U, 49938368U, 50069056U, 50200256U, 50331584U, 50462656U, 50593472U,
50724032U, 50853952U, 50986048U, 51117632U, 51248576U, 51379904U, 51510848U,
51641792U, 51773248U, 51903296U, 52035136U, 52164032U, 52297664U, 52427968U,
52557376U, 52690112U, 52821952U, 52952896U, 53081536U, 53213504U, 53344576U,
53475776U, 53608384U, 53738816U, 53870528U, 54000832U, 54131776U, 54263744U,
54394688U, 54525248U, 54655936U, 54787904U, 54918592U, 55049152U, 55181248U,
55312064U, 55442752U, 55574336U, 55705024U, 55836224U, 55967168U, 56097856U,
56228672U, 56358592U, 56490176U, 56621888U, 56753728U, 56884928U, 57015488U,
57146816U, 57278272U, 57409216U, 57540416U, 57671104U, 57802432U, 57933632U,
58064576U, 58195264U, 58326976U, 58457408U, 58588864U, 58720192U, 58849984U,
58981696U, 59113024U, 59243456U, 59375552U, 59506624U, 59637568U, 59768512U,
59897792U, 60030016U, 60161984U, 60293056U, 60423872U, 60554432U, 60683968U,
60817216U, 60948032U, 61079488U, 61209664U, 61341376U, 61471936U, 61602752U,
61733696U, 61865792U, 61996736U, 62127808U, 62259136U, 62389568U, 62520512U,
62651584U, 62781632U, 62910784U, 63045056U, 63176128U, 63307072U, 63438656U,
63569216U, 63700928U, 63831616U, 63960896U, 64093888U, 64225088U, 64355392U,
64486976U, 64617664U, 64748608U, 64879424U, 65009216U, 65142464U, 65273792U,
65402816U, 65535424U, 65666752U, 65797696U, 65927744U, 66060224U, 66191296U,
66321344U, 66453056U, 66584384U, 66715328U, 66846656U, 66977728U, 67108672U,
67239104U, 67370432U, 67501888U, 67631296U, 67763776U, 67895104U, 68026304U,
68157248U, 68287936U, 68419264U, 68548288U, 68681408U, 68811968U, 68942912U,
69074624U, 69205568U, 69337024U, 69467584U, 69599168U, 69729472U, 69861184U,
69989824U, 70122944U, 70253888U, 70385344U, 70515904U, 70647232U, 70778816U,
70907968U, 71040832U, 71171648U, 71303104U, 71432512U, 71564992U, 71695168U,
71826368U, 71958464U, 72089536U, 72219712U, 72350144U, 72482624U, 72613568U,
72744512U, 72875584U, 73006144U, 73138112U, 73268672U, 73400128U, 73530944U,
73662272U, 73793344U, 73924544U, 74055104U, 74185792U, 74316992U, 74448832U,
74579392U, 74710976U, 74841664U, 74972864U, 75102784U, 75233344U, 75364544U,
75497024U, 75627584U, 75759296U, 75890624U, 76021696U, 76152256U, 76283072U,
76414144U, 76545856U, 76676672U, 76806976U, 76937792U, 77070016U, 77200832U,
77331392U, 77462464U, 77593664U, 77725376U, 77856448U, 77987776U, 78118336U,
78249664U, 78380992U, 78511424U, 78642496U, 78773056U, 78905152U, 79033664U,
79166656U, 79297472U, 79429568U, 79560512U, 79690816U, 79822784U, 79953472U,
80084672U, 80214208U, 80346944U, 80477632U, 80608576U, 80740288U, 80870848U,
81002048U, 81133504U, 81264448U, 81395648U, 81525952U, 81657536U, 81786304U,
81919808U, 82050112U, 82181312U, 82311616U, 82443968U, 82573376U, 82705984U,
82835776U, 82967744U, 83096768U, 83230528U, 83359552U, 83491264U, 83622464U,
83753536U, 83886016U, 84015296U, 84147776U, 84277184U, 84409792U, 84540608U,
84672064U, 84803008U, 84934336U, 85065152U, 85193792U, 85326784U, 85458496U,
85589312U, 85721024U, 85851968U, 85982656U, 86112448U, 86244416U, 86370112U,
86506688U, 86637632U, 86769344U, 86900672U, 87031744U, 87162304U, 87293632U,
87424576U, 87555392U, 87687104U, 87816896U, 87947968U, 88079168U, 88211264U,
88341824U, 88473152U, 88603712U, 88735424U, 88862912U, 88996672U, 89128384U,
89259712U, 89390272U, 89521984U, 89652544U, 89783872U, 89914816U, 90045376U,
90177088U, 90307904U, 90438848U, 90569152U, 90700096U, 90832832U, 90963776U,
91093696U, 91223744U, 91356992U, 91486784U, 91618496U, 91749824U, 91880384U,
92012224U, 92143552U, 92273344U, 92405696U, 92536768U, 92666432U, 92798912U,
92926016U, 93060544U, 93192128U, 93322816U, 93453632U, 93583936U, 93715136U,
93845056U, 93977792U, 94109504U, 94240448U, 94371776U, 94501184U, 94632896U,
94764224U, 94895552U, 95023424U, 95158208U, 95287744U, 95420224U, 95550016U,
95681216U, 95811904U, 95943872U, 96075328U, 96203584U, 96337856U, 96468544U,
96599744U, 96731072U, 96860992U, 96992576U, 97124288U, 97254848U, 97385536U,
97517248U, 97647808U, 97779392U, 97910464U, 98041408U, 98172608U, 98303168U,
98434496U, 98565568U, 98696768U, 98827328U, 98958784U, 99089728U, 99220928U,
99352384U, 99482816U, 99614272U, 99745472U, 99876416U, 100007104U,
100138048U, 100267072U, 100401088U, 100529984U, 100662592U, 100791872U,
100925248U, 101056064U, 101187392U, 101317952U, 101449408U, 101580608U,
101711296U, 101841728U, 101973824U, 102104896U, 102235712U, 102366016U,
102498112U, 102628672U, 102760384U, 102890432U, 103021888U, 103153472U,
103284032U, 103415744U, 103545152U, 103677248U, 103808576U, 103939648U,
104070976U, 104201792U, 104332736U, 104462528U, 104594752U, 104725952U,
104854592U, 104988608U, 105118912U, 105247808U, 105381184U, 105511232U,
105643072U, 105774784U, 105903296U, 106037056U, 106167872U, 106298944U,
106429504U, 106561472U, 106691392U, 106822592U, 106954304U, 107085376U,
107216576U, 107346368U, 107478464U, 107609792U, 107739712U, 107872192U,
108003136U, 108131392U, 108265408U, 108396224U, 108527168U, 108657344U,
108789568U, 108920384U, 109049792U, 109182272U, 109312576U, 109444928U,
109572928U, 109706944U, 109837888U, 109969088U, 110099648U, 110230976U,
110362432U, 110492992U, 110624704U, 110755264U, 110886208U, 111017408U,
111148864U, 111279296U, 111410752U, 111541952U, 111673024U, 111803456U,
111933632U, 112066496U, 112196416U, 112328512U, 112457792U, 112590784U,
112715968U, 112852672U, 112983616U, 113114944U, 113244224U, 113376448U,
113505472U, 113639104U, 113770304U, 113901376U, 114031552U, 114163264U,
114294592U, 114425536U, 114556864U, 114687424U, 114818624U, 114948544U,
115080512U, 115212224U, 115343296U, 115473472U, 115605184U, 115736128U,
115867072U, 115997248U, 116128576U, 116260288U, 116391488U, 116522944U,
116652992U, 116784704U, 116915648U, 117046208U, 117178304U, 117308608U,
117440192U, 117569728U, 117701824U, 117833024U, 117964096U, 118094656U,
118225984U, 118357312U, 118489024U, 118617536U, 118749632U, 118882112U,
119012416U, 119144384U, 119275328U, 119406016U, 119537344U, 119668672U,
119798464U, 119928896U, 120061376U, 120192832U, 120321728U, 120454336U,
120584512U, 120716608U, 120848192U, 120979136U, 121109056U, 121241408U,
121372352U, 121502912U, 121634752U, 121764416U, 121895744U, 122027072U,
122157632U, 122289088U, 122421184U, 122550592U, 122682944U, 122813888U,
122945344U, 123075776U, 123207488U, 123338048U, 123468736U, 123600704U,
123731264U, 123861952U, 123993664U, 124124608U, 124256192U, 124386368U,
124518208U, 124649024U, 124778048U, 124911296U, 125041088U, 125173696U,
125303744U, 125432896U, 125566912U, 125696576U, 125829056U, 125958592U,
126090304U, 126221248U, 126352832U, 126483776U, 126615232U, 126746432U,
126876608U, 127008704U, 127139392U, 127270336U, 127401152U, 127532224U,
127663552U, 127794752U, 127925696U, 128055232U, 128188096U, 128319424U,
128449856U, 128581312U, 128712256U, 128843584U, 128973632U, 129103808U,
129236288U, 129365696U, 129498944U, 129629888U, 129760832U, 129892288U,
130023104U, 130154048U, 130283968U, 130416448U, 130547008U, 130678336U,
130807616U, 130939456U, 131071552U, 131202112U, 131331776U, 131464384U,
131594048U, 131727296U, 131858368U, 131987392U, 132120256U, 132250816U,
132382528U, 132513728U, 132644672U, 132774976U, 132905792U, 133038016U,
133168832U, 133299392U, 133429312U, 133562048U, 133692992U, 133823296U,
133954624U, 134086336U, 134217152U, 134348608U, 134479808U, 134607296U,
134741056U, 134872384U, 135002944U, 135134144U, 135265472U, 135396544U,
135527872U, 135659072U, 135787712U, 135921472U, 136052416U, 136182848U,
136313792U, 136444864U, 136576448U, 136707904U, 136837952U, 136970048U,
137099584U, 137232064U, 137363392U, 137494208U, 137625536U, 137755712U,
137887424U, 138018368U, 138149824U, 138280256U, 138411584U, 138539584U,
138672832U, 138804928U, 138936128U, 139066688U, 139196864U, 139328704U,
139460032U, 139590208U, 139721024U, 139852864U, 139984576U, 140115776U,
140245696U, 140376512U, 140508352U, 140640064U, 140769856U, 140902336U,
141032768U, 141162688U, 141294016U, 141426496U, 141556544U, 141687488U,
141819584U, 141949888U, 142080448U, 142212544U, 142342336U, 142474432U,
142606144U, 142736192U, 142868288U, 142997824U, 143129408U, 143258944U,
143392448U, 143523136U, 143653696U, 143785024U, 143916992U, 144045632U,
144177856U, 144309184U, 144440768U, 144570688U, 144701888U, 144832448U,
144965056U, 145096384U, 145227584U, 145358656U, 145489856U, 145620928U,
145751488U, 145883072U, 146011456U, 146144704U, 146275264U, 146407232U,
146538176U, 146668736U, 146800448U, 146931392U, 147062336U, 147193664U,
147324224U, 147455936U, 147586624U, 147717056U, 147848768U, 147979456U,
148110784U, 148242368U, 148373312U, 148503232U, 148635584U, 148766144U,
148897088U, 149028416U, 149159488U, 149290688U, 149420224U, 149551552U,
149683136U, 149814976U, 149943616U, 150076352U, 150208064U, 150338624U,
150470464U, 150600256U, 150732224U, 150862784U, 150993088U, 151125952U,
151254976U, 151388096U, 151519168U, 151649728U, 151778752U, 151911104U,
152042944U, 152174144U, 152304704U, 152435648U, 152567488U, 152698816U,
152828992U, 152960576U, 153091648U, 153222976U, 153353792U, 153484096U,
153616192U, 153747008U, 153878336U, 154008256U, 154139968U, 154270912U,
154402624U, 154533824U, 154663616U, 154795712U, 154926272U, 155057984U,
155188928U, 155319872U, 155450816U, 155580608U, 155712064U, 155843392U,
155971136U, 156106688U, 156237376U, 156367424U, 156499264U, 156630976U,
156761536U, 156892352U, 157024064U, 157155008U, 157284416U, 157415872U,
157545536U, 157677248U, 157810496U, 157938112U, 158071744U, 158203328U,
158334656U, 158464832U, 158596288U, 158727616U, 158858048U, 158988992U,
159121216U, 159252416U, 159381568U, 159513152U, 159645632U, 159776192U,
159906496U, 160038464U, 160169536U, 160300352U, 160430656U, 160563008U,
160693952U, 160822208U, 160956352U, 161086784U, 161217344U, 161349184U,
161480512U, 161611456U, 161742272U, 161873216U, 162002752U, 162135872U,
162266432U, 162397888U, 162529216U, 162660032U, 162790976U, 162922048U,
163052096U, 163184576U, 163314752U, 163446592U, 163577408U, 163707968U,
163839296U, 163969984U, 164100928U, 164233024U, 164364224U, 164494912U,
164625856U, 164756672U, 164887616U, 165019072U, 165150016U, 165280064U,
165412672U, 165543104U, 165674944U, 165805888U, 165936832U, 166067648U,
166198336U, 166330048U, 166461248U, 166591552U, 166722496U, 166854208U,
166985408U, 167116736U, 167246656U, 167378368U, 167508416U, 167641024U,
167771584U, 167903168U, 168034112U, 168164032U, 168295744U, 168427456U,
168557632U, 168688448U, 168819136U, 168951616U, 169082176U, 169213504U,
169344832U, 169475648U, 169605952U, 169738048U, 169866304U, 169999552U,
170131264U, 170262464U, 170393536U, 170524352U, 170655424U, 170782016U,
170917696U, 171048896U, 171179072U, 171310784U, 171439936U, 171573184U,
171702976U, 171835072U, 171966272U, 172097216U, 172228288U, 172359232U,
172489664U, 172621376U, 172747712U, 172883264U, 173014208U, 173144512U,
173275072U, 173407424U, 173539136U, 173669696U, 173800768U, 173931712U,
174063424U, 174193472U, 174325696U, 174455744U, 174586816U, 174718912U,
174849728U, 174977728U, 175109696U, 175242688U, 175374272U, 175504832U,
175636288U, 175765696U, 175898432U, 176028992U, 176159936U, 176291264U,
176422592U, 176552512U, 176684864U, 176815424U, 176946496U, 177076544U,
177209152U, 177340096U, 177470528U, 177600704U, 177731648U, 177864256U,
177994816U, 178126528U, 178257472U, 178387648U, 178518464U, 178650176U,
178781888U, 178912064U, 179044288U, 179174848U, 179305024U, 179436736U,
179568448U, 179698496U, 179830208U, 179960512U, 180092608U, 180223808U,
180354752U, 180485696U, 180617152U, 180748096U, 180877504U, 181009984U,
181139264U, 181272512U, 181402688U, 181532608U, 181663168U, 181795136U,
181926592U, 182057536U, 182190016U, 182320192U, 182451904U, 182582336U,
182713792U, 182843072U, 182976064U, 183107264U, 183237056U, 183368384U,
183494848U, 183631424U, 183762752U, 183893824U, 184024768U, 184154816U,
184286656U, 184417984U, 184548928U, 184680128U, 184810816U, 184941248U,
185072704U, 185203904U, 185335616U, 185465408U, 185596352U, 185727296U,
185859904U, 185989696U, 186121664U, 186252992U, 186383552U, 186514112U,
186645952U, 186777152U, 186907328U, 187037504U, 187170112U, 187301824U,
187429184U, 187562048U, 187693504U, 187825472U, 187957184U, 188087104U,
188218304U, 188349376U, 188481344U, 188609728U, 188743616U, 188874304U,
189005248U, 189136448U, 189265088U, 189396544U, 189528128U, 189660992U,
189791936U, 189923264U, 190054208U, 190182848U, 190315072U, 190447424U,
190577984U, 190709312U, 190840768U, 190971328U, 191102656U, 191233472U,
191364032U, 191495872U, 191626816U, 191758016U, 191888192U, 192020288U,
192148928U, 192282176U, 192413504U, 192542528U, 192674752U, 192805952U,
192937792U, 193068608U, 193198912U, 193330496U, 193462208U, 193592384U,
193723456U, 193854272U, 193985984U, 194116672U, 194247232U, 194379712U,
194508352U, 194641856U, 194772544U, 194900672U, 195035072U, 195166016U,
195296704U, 195428032U, 195558592U, 195690304U, 195818176U, 195952576U,
196083392U, 196214336U, 196345792U, 196476736U, 196607552U, 196739008U,
196869952U, 197000768U, 197130688U, 197262784U, 197394368U, 197523904U,
197656384U, 197787584U, 197916608U, 198049472U, 198180544U, 198310208U,
198442432U, 198573632U, 198705088U, 198834368U, 198967232U, 199097792U,
199228352U, 199360192U, 199491392U, 199621696U, 199751744U, 199883968U,
200014016U, 200146624U, 200276672U, 200408128U, 200540096U, 200671168U,
200801984U, 200933312U, 201062464U, 201194944U, 201326144U, 201457472U,
201588544U, 201719744U, 201850816U, 201981632U, 202111552U, 202244032U,
202374464U, 202505152U, 202636352U, 202767808U, 202898368U, 203030336U,
203159872U, 203292608U, 203423296U, 203553472U, 203685824U, 203816896U,
203947712U, 204078272U, 204208192U, 204341056U, 204472256U, 204603328U,
204733888U, 204864448U, 204996544U, 205125568U, 205258304U, 205388864U,
205517632U, 205650112U, 205782208U, 205913536U, 206044736U, 206176192U,
206307008U, 206434496U, 206569024U, 206700224U, 206831168U, 206961856U,
207093056U, 207223616U, 207355328U, 207486784U, 207616832U, 207749056U,
207879104U, 208010048U, 208141888U, 208273216U, 208404032U, 208534336U,
208666048U, 208796864U, 208927424U, 209059264U, 209189824U, 209321792U,
209451584U, 209582656U, 209715136U, 209845568U, 209976896U, 210106432U,
210239296U, 210370112U, 210501568U, 210630976U, 210763712U, 210894272U,
211024832U, 211156672U, 211287616U, 211418176U, 211549376U, 211679296U,
211812032U, 211942592U, 212074432U, 212204864U, 212334016U, 212467648U,
212597824U, 212727616U, 212860352U, 212991424U, 213120832U, 213253952U,
213385024U, 213515584U, 213645632U, 213777728U, 213909184U, 214040128U,
214170688U, 214302656U, 214433728U, 214564544U, 214695232U, 214826048U,
214956992U, 215089088U, 215219776U, 215350592U, 215482304U, 215613248U,
215743552U, 215874752U, 216005312U, 216137024U, 216267328U, 216399296U,
216530752U, 216661696U, 216790592U, 216923968U, 217054528U, 217183168U,
217316672U, 217448128U, 217579072U, 217709504U, 217838912U, 217972672U,
218102848U, 218233024U, 218364736U, 218496832U, 218627776U, 218759104U,
218888896U, 219021248U, 219151936U, 219281728U, 219413056U, 219545024U,
219675968U, 219807296U, 219938624U, 220069312U, 220200128U, 220331456U,
220461632U, 220592704U, 220725184U, 220855744U, 220987072U, 221117888U,
221249216U, 221378368U, 221510336U, 221642048U, 221772736U, 221904832U,
222031808U, 222166976U, 222297536U, 222428992U, 222559936U, 222690368U,
222820672U, 222953152U, 223083968U, 223213376U, 223345984U, 223476928U,
223608512U, 223738688U, 223869376U, 224001472U, 224132672U, 224262848U,
224394944U, 224524864U, 224657344U, 224788288U, 224919488U, 225050432U,
225181504U, 225312704U, 225443776U, 225574592U, 225704768U, 225834176U,
225966784U, 226097216U, 226229824U, 226360384U, 226491712U, 226623424U,
226754368U, 226885312U, 227015104U, 227147456U, 227278528U, 227409472U,
227539904U, 227669696U, 227802944U, 227932352U, 228065216U, 228196288U,
228326464U, 228457792U, 228588736U, 228720064U, 228850112U, 228981056U,
229113152U, 229243328U, 229375936U, 229505344U, 229636928U, 229769152U,
229894976U, 230030272U, 230162368U, 230292416U, 230424512U, 230553152U,
230684864U, 230816704U, 230948416U, 231079616U, 231210944U, 231342016U,
231472448U, 231603776U, 231733952U, 231866176U, 231996736U, 232127296U,
232259392U, 232388672U, 232521664U, 232652608U, 232782272U, 232914496U,
233043904U, 233175616U, 233306816U, 233438528U, 233569984U, 233699776U,
233830592U, 233962688U, 234092224U, 234221888U, 234353984U, 234485312U,
234618304U, 234749888U, 234880832U, 235011776U, 235142464U, 235274048U,
235403456U, 235535936U, 235667392U, 235797568U, 235928768U, 236057152U,
236190272U, 236322752U, 236453312U, 236583616U, 236715712U, 236846528U,
236976448U, 237108544U, 237239104U, 237371072U, 237501632U, 237630784U,
237764416U, 237895232U, 238026688U, 238157632U, 238286912U, 238419392U,
238548032U, 238681024U, 238812608U, 238941632U, 239075008U, 239206336U,
239335232U, 239466944U, 239599168U, 239730496U, 239861312U, 239992384U,
240122816U, 240254656U, 240385856U, 240516928U, 240647872U, 240779072U,
240909632U, 241040704U, 241171904U, 241302848U, 241433408U, 241565248U,
241696192U, 241825984U, 241958848U, 242088256U, 242220224U, 242352064U,
242481856U, 242611648U, 242744896U, 242876224U, 243005632U, 243138496U,
243268672U, 243400384U, 243531712U, 243662656U, 243793856U, 243924544U,
244054592U, 244187072U, 244316608U, 244448704U, 244580032U, 244710976U,
244841536U, 244972864U, 245104448U, 245233984U, 245365312U, 245497792U,
245628736U, 245759936U, 245889856U, 246021056U, 246152512U, 246284224U,
246415168U, 246545344U, 246675904U, 246808384U, 246939584U, 247070144U,
247199552U, 247331648U, 247463872U, 247593536U, 247726016U, 247857088U,
247987648U, 248116928U, 248249536U, 248380736U, 248512064U, 248643008U,
248773312U, 248901056U, 249036608U, 249167552U, 249298624U, 249429184U,
249560512U, 249692096U, 249822784U, 249954112U, 250085312U, 250215488U,
250345792U, 250478528U, 250608704U, 250739264U, 250870976U, 251002816U,
251133632U, 251263552U, 251395136U, 251523904U, 251657792U, 251789248U,
251919424U, 252051392U, 252182464U, 252313408U, 252444224U, 252575552U,
252706624U, 252836032U, 252968512U, 253099712U, 253227584U, 253361728U,
253493056U, 253623488U, 253754432U, 253885504U, 254017216U, 254148032U,
254279488U, 254410432U, 254541376U, 254672576U, 254803264U, 254933824U,
255065792U, 255196736U, 255326528U, 255458752U, 255589952U, 255721408U,
255851072U, 255983296U, 256114624U, 256244416U, 256374208U, 256507712U,
256636096U, 256768832U, 256900544U, 257031616U, 257162176U, 257294272U,
257424448U, 257555776U, 257686976U, 257818432U, 257949632U, 258079552U,
258211136U, 258342464U, 258473408U, 258603712U, 258734656U, 258867008U,
258996544U, 259127744U, 259260224U, 259391296U, 259522112U, 259651904U,
259784384U, 259915328U, 260045888U, 260175424U, 260308544U, 260438336U,
260570944U, 260700992U, 260832448U, 260963776U, 261092672U, 261226304U,
261356864U, 261487936U, 261619648U, 261750592U, 261879872U, 262011968U,
262143424U, 262274752U, 262404416U, 262537024U, 262667968U, 262799296U,
262928704U, 263061184U, 263191744U, 263322944U, 263454656U, 263585216U,
263716672U, 263847872U, 263978944U, 264108608U, 264241088U, 264371648U,
264501184U, 264632768U, 264764096U, 264895936U, 265024576U, 265158464U,
265287488U, 265418432U, 265550528U, 265681216U, 265813312U, 265943488U,
266075968U, 266206144U, 266337728U, 266468032U, 266600384U, 266731072U,
266862272U, 266993344U, 267124288U, 267255616U, 267386432U, 267516992U,
267648704U, 267777728U, 267910592U, 268040512U, 268172096U, 268302784U,
268435264U, 268566208U, 268696256U, 268828096U, 268959296U, 269090368U,
269221312U, 269352256U, 269482688U, 269614784U, 269745856U, 269876416U,
270007616U, 270139328U, 270270272U, 270401216U, 270531904U, 270663616U,
270791744U, 270924736U, 271056832U, 271186112U, 271317184U, 271449536U,
271580992U, 271711936U, 271843136U, 271973056U, 272105408U, 272236352U,
272367296U, 272498368U, 272629568U, 272759488U, 272891456U, 273022784U,
273153856U, 273284672U, 273415616U, 273547072U, 273677632U, 273808448U,
273937088U, 274071488U, 274200896U, 274332992U, 274463296U, 274595392U,
274726208U, 274857536U, 274988992U, 275118656U, 275250496U, 275382208U,
275513024U, 275643968U, 275775296U, 275906368U, 276037184U, 276167872U,
276297664U, 276429376U, 276560576U, 276692672U, 276822976U, 276955072U,
277085632U, 277216832U, 277347008U, 277478848U, 277609664U, 277740992U,
277868608U, 278002624U, 278134336U, 278265536U, 278395328U, 278526784U,
278657728U, 278789824U, 278921152U, 279052096U, 279182912U, 279313088U,
279443776U, 279576256U, 279706048U, 279838528U, 279969728U, 280099648U,
280230976U, 280361408U, 280493632U, 280622528U, 280755392U, 280887104U,
281018176U, 281147968U, 281278912U, 281411392U, 281542592U, 281673152U,
281803712U, 281935552U, 282066496U, 282197312U, 282329024U, 282458816U,
282590272U, 282720832U, 282853184U, 282983744U, 283115072U, 283246144U,
283377344U, 283508416U, 283639744U, 283770304U, 283901504U, 284032576U,
284163136U, 284294848U, 284426176U, 284556992U, 284687296U, 284819264U,
284950208U, 285081536U
};
#ifdef __cplusplus

136
libethash/ethash.h

@ -1,19 +1,20 @@
/*
This file is part of cpp-ethereum.
This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify
ethash 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,
ethash 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/>.
along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethash.h
* @date 2015
*/
@ -23,70 +24,115 @@
#include <stdbool.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include "compiler.h"
#define REVISION 19
#define DAGSIZE_BYTES_INIT 1073741824U // 2**30
#define DAG_GROWTH 113000000U
#define EPOCH_LENGTH 30000U
#define MIX_BYTES 128
#define DAG_PARENTS 256
#define CACHE_ROUNDS 3
#define ACCESSES 64
#define ETHASH_REVISION 23
#define ETHASH_DATASET_BYTES_INIT 1073741824U // 2**30
#define ETHASH_DATASET_BYTES_GROWTH 8388608U // 2**23
#define ETHASH_CACHE_BYTES_INIT 1073741824U // 2**24
#define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17
#define ETHASH_EPOCH_LENGTH 30000U
#define ETHASH_MIX_BYTES 128
#define ETHASH_HASH_BYTES 64
#define ETHASH_DATASET_PARENTS 256
#define ETHASH_CACHE_ROUNDS 3
#define ETHASH_ACCESSES 64
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ethash_params {
size_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
size_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
} ethash_params;
typedef struct ethash_return_value {
uint8_t result[32];
uint8_t mix_hash[32];
uint8_t result[32];
uint8_t mix_hash[32];
} ethash_return_value;
size_t ethash_get_datasize(const uint32_t block_number);
size_t ethash_get_cachesize(const uint32_t block_number);
uint64_t ethash_get_datasize(const uint32_t block_number);
uint64_t ethash_get_cachesize(const uint32_t block_number);
// initialize the parameters
static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
params->full_size = ethash_get_datasize(block_number);
params->cache_size = ethash_get_cachesize(block_number);
params->full_size = ethash_get_datasize(block_number);
params->cache_size = ethash_get_cachesize(block_number);
}
typedef struct ethash_cache {
void *mem;
} ethash_cache;
/***********************************
* OLD API *************************
***********************************
******************** (deprecated) *
***********************************/
void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]);
void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache);
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number);
void ethash_mkcache(void *cache, ethash_params const *params, const uint8_t seed[32]);
void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_compute_full_data(void *mem, ethash_params const *params, void const *cache);
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { ethash_cache c; c.mem = cache; ethash_mkcache(&c, params, seed); }
static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_cache c; c.mem = (void*)cache; ethash_light(ret, &c, params, header_hash, nonce); }
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_cache c; c.mem = (void*)cache; ethash_compute_full_data(full, params, &c); }
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_full(ret, full, params, header_hash, nonce); }
static inline int ethash_check_difficulty(
const uint8_t hash[32],
const uint8_t difficulty[32]) {
// Difficulty is big endian
for (int i = 0; i < 32; i++) {
if (hash[i] == difficulty[i]) continue;
return hash[i] < difficulty[i];
}
/***********************************
* NEW API *************************
***********************************/
// TODO: compute params and seed in ethash_new_light; it should take only block_number
// TODO: store params in ethash_light_t/ethash_full_t to avoid having to repass into compute/new_full
typedef uint8_t const ethash_seedhash_t[32];
typedef void const* ethash_light_t;
static inline ethash_light_t ethash_new_light(ethash_params const* params, ethash_seedhash_t seed) {
void* ret = malloc(params->cache_size);
ethash_mkcache(ret, params, seed);
return ret;
}
static inline void ethash_compute_light(ethash_return_value *ret, ethash_light_t light, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
ethash_light(ret, light, params, header_hash, nonce);
}
static inline void ethash_delete_light(ethash_light_t light) {
free((void*)light);
}
typedef void const* ethash_full_t;
static inline ethash_full_t ethash_new_full(ethash_params const* params, ethash_light_t light) {
void* ret = malloc(params->full_size);
ethash_compute_full_data(ret, params, light);
return ret;
}
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) {
ethash_compute_full_data(full, params, cache);
}
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
ethash_full(ret, full, params, header_hash, nonce);
}
/// @brief Compare two s256-bit big-endian values.
/// @returns 1 if @a a is less than or equal to @a b, 0 otherwise.
/// Both parameters are 256-bit big-endian values.
static inline int ethash_leq_be256(const uint8_t a[32], const uint8_t b[32]) {
// Boundary is big endian
for (int i = 0; i < 32; i++) {
if (a[i] == b[i])
continue;
return a[i] < b[i];
}
return 1;
}
int ethash_quick_check_difficulty(
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32],
const uint8_t difficulty[32]);
/// Perofrms a cursory check on the validity of the nonce.
/// @returns 1 if the nonce may possibly be valid for the given header_hash & boundary.
/// @p boundary equivalent to 2 ^ 256 / block_difficulty, represented as a 256-bit big-endian.
int ethash_preliminary_check_boundary(
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32],
const uint8_t boundary[32]);
#define ethash_quick_check_difficulty ethash_preliminary_check_boundary
#define ethash_check_difficulty ethash_leq_be256
#ifdef __cplusplus
}

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

Loading…
Cancel
Save